您的位置:首页 > 编程语言 > Java开发

Java 动态代理

2016-02-25 11:46 344 查看
一、动态代理的由来
代理是指:给每个具体类写一个代理类,以后要使用某个具体的类时,只要创建它的代理类的对象,然后调用代理类的方法就可以了,可是如果现在有很多具体的类,那就需要创建很多的代理类才可以,这样显然很不合适,那动态代理就应运而生。

二、Java实现动态代理有2种方式:
1、JDK实现动态代理,但是它需要实现类通过接口定义业务方法,对于没有接口的类是无法实现的;
2、CGLib,它采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用。

JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。

三、JDK的实现
此类型的动态代理使用到了一个接口InvocationHandler和一个代理类Proxy,这两个类配合使用即可实现动态代理。

//接口
interface InterfaceClass {
void show() ;
}

//具体实现类A
class ClassA implements InterfaceClass {
@Override
public void show(){
System.out.println("class A") ;
}
}

//具体实现类B
class ClassB implements InterfaceClass {
@Override
public void show(){
System.out.println("class B") ;
}
}

//动态代理类,实现InvocationHandler接口

class Invoker implements InvocationHandler {
InterfaceClass ia ;

public Invoker(InterfaceClass ia) {
this.ia = ia ;
}

@Override
public Object invoke(Object proxy, Method method, Object[] arg) throws Throwable {
method.invoke(ia, arg) ;
return null ;
}
}

// Test
class DynamicProxyTest{
public static void main(String[] args){
// 创建具体类ClassA的处理对象
Invoker invoker1 = new Invoker(new ClassA());
// 获得具体类ClassA的代理
InterfaceClass ic1 = (InterfaceClass)Proxy.newProxyInstance(InterfaceClass.class.getClassLoader(), new Class[]{InterfaceClass.class}, invoker1);
ic1.show() ;

// classB也是如此
}
}


四、CGLib实现

public class CGLIBProxy implements MethodInterceptor{
private Enhancer enhancer = new Enhancer() ;

public Object getProxy(Class clazz) {
// 设置父类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
// 通过字节码技术动态创建子类实力
return enhancer.create() ;
}

// 所有的方法都会被这个方法所拦截,该类实现了子类的方法与代理的方法。getProxy(SuperClass.class)方法通过入参即父类的字节码,通过扩展父类的class类创建代理对象。intercept()方法拦截所有目标类方法的调用,obj表示目标类的实例,args为方法动态入参,proxy为代理类实例。
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodproxy) throws Throwable{
Object result = methodproxy.invokerSuper(obj, args) ;
return result ;
}
}

public class UserServiceImpl{
public void sayHello() {
System.out.println("sayHello method") ;
}

public void sayBye() {
System.out.println("sayBye method") ;
}
}
// Test
public class Test{
public static void main(String[] args) {
CGLIBProxy proxy = new CGLIBProxy() ;

UserServiceImpl impl = (UserServiceImpl)proxy.getProxy(UserServiceImpl.class) ;
impl.sayHello() ;
}

}


六、比较两种方式的优缺点

CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib更合适,反之使用JDK方式要更好些。同时,用于CGLib采用的动态代理创建子类的方式,对于final方法,无法进行处理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: