java动态代理与cglib

转载自:http://langyu.iteye.com/blog/410071

              http://www.cnblogs.com/xiaoluo501395377/p/3383130.html

 

Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类:

    1. InvocationHandler:该接口中仅定义了一个invoke方法。每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。

 1: public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{...}

    第一个参数obj一般是指要代理的类,method是被代理的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。

    2. Proxy:该类的作用就是用来动态创建一个代理对象的类,其中主要包含以下方法:

 1: public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException{…}
 2: //获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组.

 1: public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException{…}
 2: //返回代理类的一个实例,返回后的代理类可以当作被代理类使用.

    loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载。

    interfaces: 一个Interface对象的数组,表示的是要给需要代理的对象提供一组什么接口,如果提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样就能调用这组接口中的方法了。

    h: 一个InvocationHandler对象,表示的是当这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上。


    Proxy.newProxyInstance (ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)做了以下几件事.

    (1)根据参数loader和interfaces调用getProxyClass(loader, interfaces)创建代理类$Proxy. $Proxy0类实现了interfaces的接口,并继承了Proxy类.

    (2)实例化$Proxy0并在构造方法中把loader传过去, 接着$Proxy0调用父类Proxy的构造器,为h赋值。接着把得到的$Proxy0实例强制转换成代理类. 当执行代理类的方法时,就调用了$Proxy0类中的方法.在执行代理类方法中,调用父类Proxy中的h的invoke()方法.即InvocationHandler.invoke()。

示例:

 1: package com.zero;
 2:  
 3: public interface IHello {
 4: void say();
 5: }

 1: package com.zero;
 2:  
 3: public class HelloImpl implements IHello {
 4:  
 5: @Override
 6: public void say() {
 7: // TODO Auto-generated method stub
 8: System.out.println("Say hello!");
 9: }
 10: }

 1: package com.zero;
 2:  
 3: import java.lang.reflect.InvocationHandler;
 4: import java.lang.reflect.Method;
 5:  
 6: public class JDKProxyHandler implements InvocationHandler {
 7: // 这个就是我们要代理的真实对象
 8: private Object realObject;
 9:  
 10: // 构造方法,给我们要代理的真实对象赋初值
 11: public JDKProxyHandler(Object target) {
 12: this.realObject = target;
 13: }
 14:  
 15: @Override
 16: public Object invoke(Object proxy, Method method, Object[] args)
 17: throws Throwable {
 18: // TODO Auto-generated method stub
 19: System.out.println("jdk...invoke() begin");
 20: System.out.println(method);
 21: Object result = method.invoke(realObject, args);
 22: System.out.println("jdk...invoke() end");
 23: return result;
 24: }
 25: }

 1: package com.zero;
 2:  
 3: import java.lang.reflect.Proxy;
 4:  
 5: public class JDKProxyTest {
 6:  
 7: public static void main(String[] args) {
 8: // TODO Auto-generated method stub
 9: HelloImpl impl = new HelloImpl();
 10: // 这里把handler与impl新生成的代理类相关联
 11: JDKProxyHandler handler = new JDKProxyHandler(impl);
 12: // 获得代理类($Proxy0 extends Proxy implements IHello)的实例.
 13: IHello hello = (IHello) Proxy.newProxyInstance(impl.getClass()
 14: .getClassLoader(), impl.getClass().getInterfaces(), handler);
 15: // 这里无论访问哪个方法,都是会把请求转发到handler.invoke
 16: hello.say();
 17: System.out.println(hello.getClass());
 18: //class com.sun.proxy.$Proxy0
 19: }
 20: }


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

示例:

 1: package com.zero;
 2:  
 3: import java.lang.reflect.Method;
 4:  
 5: import org.springframework.cglib.proxy.Enhancer;
 6: import org.springframework.cglib.proxy.MethodInterceptor;
 7: import org.springframework.cglib.proxy.MethodProxy;
 8:  
 9: public class CGlibProxyHander implements MethodInterceptor {
 10: private Object target;
 11:  
 12: // target不必须使用接口
 13: public Object createProxyInstance(Object target) {
 14: this.target = target;
 15: Enhancer enhancer = new Enhancer();
 16: // 实际上是继承了目标类,覆盖目标类所有非final方法,再基础上添加新的代码
 17: // 使用Enhancer可以对任意类生成代理类,
 18: // 只要enhancer.setSuperclass(this.target.getClass());
 19: // 其实质是代理类是目标类的子类。
 20: enhancer.setSuperclass(this.target.getClass());
 21: enhancer.setCallback(this);
 22: return enhancer.create();
 23: }
 24:  
 25: // 从参数构成上,intercept的输入参数比invoke多1个,其实前3个参数对象的含义与invoke的含义是相同的
 26: // 第一个参数表示调用方法来自哪个对象;
 27: // 第二个参数表示调用方法的Method对象;
 28: // 第三个参数表示此次调用的输入参数列表;
 29: // 多出来的参数是MethodProxy 类型的,它应该是cglib生成用来代替Method对象的一个对象,
 30: // 使用MethodProxy比调用JDK自身的Method直接执行方法效率会有提升
 31: @Override
 32: public Object intercept(Object object, Method method, Object[] args,
 33: MethodProxy methodProxy) throws Throwable {
 34: Object result = null;
 35: System.out.println("CGlib代理 " + method.getName() + "()方法");
 36: result = methodProxy.invoke(this.target, args);
 37: return result;
 38: }
 39: }

 1: package com.zero;
 2:  
 3: import java.lang.reflect.Proxy;
 4:  
 5: public class CGlibProxyTest {
 6:  
 7: public static void main(String[] args) {
 8: // TODO Auto-generated method stub
 9: HelloImpl impl = new HelloImpl();
 10: CGlibProxyHander hander = new CGlibProxyHander();
 11: 
 12: IHello hello = (IHello) hander.createProxyInstance(impl);
 13: hello.say();
 14: System.out.println(hello.getClass());
 15: // class com.sun.proxy.$Proxy0
 16: }
 17: }

你可能感兴趣的:(java动态代理与cglib)