java动态代理(jdk与cglib)详细解析

JAVA的动态代理

代理模式
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
按照代理的创建时期,代理类可以分为两种。

静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。

动态代理:在程序运行时,运用反射机制动态创建而成。

首先看一下静态代理:
1、Count.java


代码如下:

package net.battier.dao;

/**
 * 定义一个账户接口
 * 
 * @author Administrator
 * 
 */ 
public interface Count { 
    // 查看账户方法 
    public void queryCount();

// 修改账户方法 
    public void updateCount();

}

2、CountImpl.java


代码如下:

package net.battier.dao.impl;

import net.battier.dao.Count;

/**
 * 委托类(包含业务逻辑)
 * 
 * @author Administrator
 * 
 */ 
public class CountImpl implements Count {

@Override 
    public void queryCount() { 
        System.out.println("查看账户方法...");

}

@Override 
    public void updateCount() { 
        System.out.println("修改账户方法...");

}

}

CountProxy.java 
package net.battier.dao.impl;

import net.battier.dao.Count;

/**
 * 这是一个代理类(增强CountImpl实现类)
 * 
 * @author Administrator
 * 
 */ 
public class CountProxy implements Count { 
    private CountImpl countImpl;

/**
     * 覆盖默认构造器
     * 
     * @param countImpl
     */ 
    public CountProxy(CountImpl countImpl) { 
        this.countImpl = countImpl; 
    }

@Override 
    public void queryCount() { 
        System.out.println("事务处理之前"); 
        // 调用委托类的方法; 
        countImpl.queryCount(); 
        System.out.println("事务处理之后"); 
    }

@Override 
    public void updateCount() { 
        System.out.println("事务处理之前"); 
        // 调用委托类的方法; 
        countImpl.updateCount(); 
        System.out.println("事务处理之后");

}

}

3、TestCount.java


代码如下:

package net.battier.test;

import net.battier.dao.impl.CountImpl; 
import net.battier.dao.impl.CountProxy;

/**
 *测试Count类
 * 
 * @author Administrator
 * 
 */ 
public class TestCount { 
    public static void main(String[] args) { 
        CountImpl countImpl = new CountImpl(); 
        CountProxy countProxy = new CountProxy(countImpl); 
        countProxy.updateCount(); 
        countProxy.queryCount();


}

观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。

再来看一下动态代理:
JDK动态代理中包含一个类和一个接口:
InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
参数说明:
Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所需要的参数

可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。

Proxy类:
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h)
                               throws IllegalArgumentException
参数说明:
ClassLoader loader:类加载器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子类实例

Ps:类加载器
在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器;
Booststrap ClassLoader:此加载器采用C++编写,一般开发中是看不到的;
Extendsion ClassLoader:用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类;
AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。

动态代理
与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。

动态代理示例:
1、BookFacade.java


代码如下:

package net.battier.dao;

public interface BookFacade { 
    public void addBook(); 
}

2、BookFacadeImpl.java


代码如下:

package net.battier.dao.impl;

import net.battier.dao.BookFacade;

public class BookFacadeImpl implements BookFacade {

@Override 
    public void addBook() { 
        System.out.println("增加图书方法。。。"); 
    }

}

BookFacadeProxy.java

package net.battier.proxy;

import java.lang.reflect.InvocationHandler; 
import java.lang.reflect.Method; 
import java.lang.reflect.Proxy;

/**
 * JDK动态代理代理类
 * 
 * @author student
 * 
 */ 
public class BookFacadeProxy implements InvocationHandler { 
    private Object target; 
    /**
     * 绑定委托对象并返回一个代理类
     * @param target
     * @return
     */ 
    public Object bind(Object target) { 
        this.target = target; 
        //取得代理对象 
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
                target.getClass().getInterfaces(), this);   //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷) 
    }

@Override 
    /**
     * 调用方法
     */ 
    public Object invoke(Object proxy, Method method, Object[] args) 
            throws Throwable { 
        Object result=null; 
        System.out.println("事物开始"); 
        //执行方法 
        result=method.invoke(target, args); 
        System.out.println("事物结束"); 
        return result; 
    }

}

3、TestProxy.java


代码如下:

package net.battier.test;

import net.battier.dao.BookFacade; 
import net.battier.dao.impl.BookFacadeImpl; 
import net.battier.proxy.BookFacadeProxy;

public class TestProxy {

public static void main(String[] args) { 
        BookFacadeProxy proxy = new BookFacadeProxy(); 
        BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl()); 
        bookProxy.addBook(); 
    }

}

但是,JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。

Cglib动态代理
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

示例
1、BookFacadeCglib.java


代码如下:

package net.battier.dao;

public interface BookFacade { 
    public void addBook(); 
}

2、BookCadeImpl1.java


代码如下:

package net.battier.dao.impl;

/**
 * 这个是没有实现接口的实现类
 * 
 * @author student
 * 
 */ 
public class BookFacadeImpl1 { 
    public void addBook() { 
        System.out.println("增加图书的普通方法..."); 
    } 
}

3、BookFacadeProxy.java


代码如下:

package net.battier.proxy;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer; 
import net.sf.cglib.proxy.MethodInterceptor; 
import net.sf.cglib.proxy.MethodProxy;

/**
 * 使用cglib动态代理
 * 
 * @author student
 * 
 */ 
public class BookFacadeCglib implements MethodInterceptor { 
    private Object target;

/**
     * 创建代理对象
     * 
     * @param target
     * @return
     */ 
    public Object getInstance(Object target) { 
        this.target = target; 
        Enhancer enhancer = new Enhancer(); 
        enhancer.setSuperclass(this.target.getClass()); 
        // 回调方法 
        enhancer.setCallback(this); 
        // 创建代理对象 
        return enhancer.create(); 
    }

@Override 
    // 回调方法 
    public Object intercept(Object obj, Method method, Object[] args, 
            MethodProxy proxy) throws Throwable { 
        System.out.println("事物开始"); 
        proxy.invokeSuper(obj, args); 
        System.out.println("事物结束"); 
        return null;

}

}

4、TestCglib.java


代码如下:

package net.battier.test;

import net.battier.dao.impl.BookFacadeImpl1; 
import net.battier.proxy.BookFacadeCglib;

public class TestCglib {

public static void main(String[] args) { 
        BookFacadeCglib cglib=new BookFacadeCglib(); 
        BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1()); 
        bookCglib.addBook(); 
    } 
}

(0)

相关推荐

  • java jdk动态代理详解

    jdk动态代理要对一个类进行代理,被代理的类必须实现至少一个接口,并且只有接口中的方法才能被代理. jdk实现动态代理一般分为三步: 1. 编写接口和实现类. 2. 写一个处理器,该处理器实现InvocationHandler接口,该接口只有一个方法,其签名为public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;可在该处理器的实现方法中,在方法调用前和调用后加入自己的代码,从而进行动态拦截

  • java实现动态代理方法浅析

    一些Java项目中在mybatis与spring整合中有MapperScannerConfigurer的使用,该类通过反向代理自动生成基于接口的动态代理类. 有鉴于此,本文浅析了java的动态代理. 本文使用动态代理模拟处理事务的拦截器. 接口: public interface UserService { public void addUser(); public void removeUser(); public void searchUser(); } 实现类: public class

  • 基于接口实现java动态代理示例

    Subject.java 复制代码 代码如下: package _20140416_; import java.util.List; public interface Subject {   public String say(String name,int age);   public List<Person> getAllList(String name);} RealSubject.java 复制代码 代码如下: package _20140416_; import java.util.

  • 代理模式之Java动态代理实现方法

    今天一个偶然的机会我突然想看看JDK的动态代理,因为以前也知道一点,而且只是简单的想测试一下使用,使用很快里就写好了这么几个接口和类:接口类:UserService.java 复制代码 代码如下: package com.yixi.proxy;public interface UserService {    public int save() ;    public void update(int id);} 实现类:UserServiceImpl.java 复制代码 代码如下: packag

  • java动态代理和cglib动态代理示例分享

    java动态代理类可以分为两种. 静态代理:由程序员创建或特定工具自动生成源代码,再对其编译.在程序运行前,代理类的.class文件就已经存在了. 动态代理:在程序运行时,运用反射机制动态创建而成. 一.首先我们进行java动态代理的演示. 现在我们有一个简单的业务接口Saying,如下: 复制代码 代码如下: package testAOP;public interface Saying {public void sayHello(String name);    public void ta

  • Java动态代理的应用详解

    动态代理其实就是java.lang.reflect.Proxy类动态的根据您指定的所有接口生成一个class byte,该class会继承Proxy类,并实现所有你指定的接口(您在参数中传入的接口数组):然后再利用您指定的classloader将 class byte加载进系统,最后生成这样一个类的对象,并初始化该对象的一些值,如invocationHandler,以即所有的接口对应的Method成员. 初始化之后将对象返回给调用的客户端.这样客户端拿到的就是一个实现你所有的接口的Proxy对象

  • 十分钟理解Java中的动态代理

    若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的. 通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类. 一.概述 1. 什么是代理 我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家"委托"代理为其销售商品.关于微商代理,首先我们从他们那里买东西时通常不知道背后的厂家究竟是谁,也就是说,"委托者"对我们来说是不可见的;其次,微商代理主要以朋友圈的人为目标客户,这就

  • java使用动态代理来实现AOP(日志记录)的实例代码

    下面是一个AOP实现的简单例子: 首先定义一些业务方法: 复制代码 代码如下: /** * Created with IntelliJ IDEA. * Author: wangjie  email:tiantian.china.2@gmail.com * Date: 13-9-23 * Time: 下午3:49 */public interface BussinessService {    public String login(String username, String password

  • JAVA提高第八篇 动态代理技术

    对于动态代理,学过AOP的应该都不会陌生,因为代理是实现AOP功能的核心和关键技术.那么今天我们将开始动态代理的学习: 一.引出动态代理 生活中代理应该是很常见的,比如你可以通过代理商去买电脑,也可以直接找厂商买电脑,最终都是买到了电脑.程序中也一样存在代理的情况,比如要为已经存在的多个具有相同接口的目标类的各个方法增加一些系统功能,例如:异常处理.日志.计算方法耗时等等,那么我们会怎么做呢? 1.会编写一个与目标类拥有相同接口的代理类,代理类的每个方法调用目标类的相同方法,然后在调用方法前后加

  • java代理模式与动态代理模式详解

    1.代理模式 所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 生活中的例子:过年加班比较忙,没空去买火车票,这时可以打个电话到附近的票务中心,叫他们帮你买张回家的火车票,当然这会附加额外的劳务费.但要清楚票务中心自己并不卖票,只有火车站才真正卖票,票务中心卖给你的票其实是通过火车站实现的.这点很重要!

随机推荐