`

动态代理

阅读更多

静态代理:由程序员创建或者特定工具生成,再对其编译。代理类在程序运行前就已经存在。
缺点:不够灵活,原接口中添加一个方法,代理类就需要进行相应地修改。

动态代理:程序运行时,通过反射机制动态创建。
优点:接口中所有的方法都被移动到一个集中的方法中处理(invoke),当接口中方法比较多时,我们可以灵活处理,不需要像静态代理那样一个一个中转。

动态代理必须实现invocationHandler接口,实现invoke方法。invoke方法就是调用被代理接口的所有方法时需要被调用的。bind方法返回的是被代理接口的一个代理对象。

public class DynamicProxy implements InvocationHandler{
     Object target;
     public Object bind(Object target){
          this.target = target;
          return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
     }
     @Override
     public Object invoke(Object proxy, Method method, Object[] args)
               throws Throwable {
          // TODO Auto-generated method stub
          Object result = null;
          System.out.println("DynamicProxy start!");
          result = method.invoke(target, args);
          System.out.println("DynamicProxy end!");
          return result;
     }
}


public class TestDynamicProxy {
     public static void main(String[] args){
          DynamicProxy dynamicProxy = new DynamicProxy();
          HelloWorld helloWorld = (HelloWorld) dynamicProxy.bind(new HelloWorldImp());
          helloWorld.print();
          helloWorld.say();
     }
}


用InvocationHandler 与 Proxy实现的动态代理有一个缺点,代理对象必须实现接口。如果没有实现接口就不能用JDK代理,这是可以使用CGLIB动态代理。实现原理是对指定目标类生成一个子类,并覆盖其中的方法增强实现。但因为采用了继承,所以不能对final修饰的类进行代理。

CGLibHelloWorldImple没有实现接口,要产生该类的动态代理不能使用JDK自带的类,可以使用CGLib
public class CGLibHelloWorldImpl {

     public void print() {
          // TODO Auto-generated method stub
          System.out.println("Hello World!");
     }


     public void say() {
          // TODO Auto-generated method stub
          System.out.println("say method!");
     }

    
     public void talk() {
          // TODO Auto-generated method stub
          System.out.println("talk!");
     }
}


//CGLibHelloWorldProxy中的getInstance方法会产生一个代理目标target的代理对象。

public class CGLibHelloWorldProxy implements MethodInterceptor{
     private Object target;
    
     /**
      * 创建代理对象
      *
      * @param target
      * @return proxy object of target
      */
     public Object getInstance(Object target){
          this.target = target;
          Enhancer enhancer = new Enhancer();
          enhancer.setSuperclass(this.target.getClass());//设置父类,返回的代理对象是target的子类,覆盖了target的方法并增强
          enhancer.setCallback(this);//回调方法
          return enhancer.create();//创建代理对象
     }

     @Override
     public Object intercept(Object obj, Method method, Object[] args,
               MethodProxy methodProxy) throws Throwable {
          Object result = null;
          System.out.println("CGLIB DynamicProxy start!");
          result = methodProxy.invoke(this.target, args);
          System.out.println("CGLIB DynamicProxy end!");
          return result;
     }
}


//代理的测试代码
public class CGLibProxyTest {
     public static void main(String[] args){
          CGLibHelloWorldProxy proxy = new CGLibHelloWorldProxy();
          CGLibHelloWorldImpl helloWorld = (CGLibHelloWorldImpl) proxy.getInstance(new CGLibHelloWorldImpl());
          System.out.println(helloWorld.getClass());
          helloWorld.say();
     }

}


两种代理生成方式的比较:
1.使用JDK的动态代理, 被代理类一定要实现了某个接口, 而使用CGLIB, 被代理类没有实现任何接口也可以实现动态代理功能,
2. 因为采用的是继承, 所以cglib无法对使用final修饰的类使用代理.
3. CGLIB的速度要远远快于JDK Proxy动态代理.
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics