zoukankan      html  css  js  c++  java
  • 实现动态代理的两种方式

    常见的实现代理的两种方式:(1)JDK动态代理(2)使用cglib产生代理

    这两种方法各有好坏。jdk动态代理是由java内部的反射机制生成字节码并生成对象来实现的,而cglib代理底层是借助asm来实现的,这个asm就是一个java字节码操纵框架,它能用来动态生成类或者增强类的功能,ASM从类文件中读入信息后,改变类的行为,分析类的信息,这就跟aop实现方式中的静态织入的是一样的,就是相当于把切面织入类的字节码文件中,以此达到拦截的作用。一般jdk动态代理用于目标类都是基于统一的接口,cglib多用于对类的代理,这些类不需要实现统一的接口。

    1.jdk动态代理

    假设我们要实现对时间的代理,首先我们先定义一个TimeHandler的类,并让这个类实现InvocationHandler的接口,在这个接口中有invoke()方法,我们需要重写这个方法

     1 public class TimeHandler implements InvocationHandler{  
     2        public Object target;//要代理的类的对象  
     3        public TimeHandler(Object target){  
     4        super();  
     5        this.target=target;  
     6        }  
     7        public Object invoke(object proxy,Method  
     8  method,Object[] args)throws Throwable{  
     9     //方法调用前可以执行比如说权限检查之类的  
    10      method.invoke(target);  
    11     //方法调用后可以执行比如说日志输出等等  
    12      return null;  
    13     }  
    14 }  

    测试方法如下

    public class Test {  
      
        public static void main(String[] args) {  
            // TODO Auto-generated method stub  
            Move car=new Car();//需要代理的类  
            TimeHandler t=new TimeHandler(car);  
            Move car1=(Move)Proxy.newProxyInstance(car.getClass().getClassLoader(), car.getClass().getInterfaces(), t);//创建代理类  
            car1.move();  
        }  
    }  

    这里解释一下很多人不理解为什么jdk动态代理的对象必须实现一个统一的接口,其实我的理解大致是代理类本身已经extends了TimeHandler,如果传入的是父类,很可能出现这种情况:

    public class $Proxy1 extends Proxy extends 传入的父类{  
          
    }  

    这个明显在java中是不允许的,Java只支持单继承,但是实现接口是完全可以的。

    2.cglib动态代理

    针对类来实现代理,对指定目标类产生一个子类,通过方法拦截技术拦截所有父类方法的调用。

    编写cglib动态代理要引入一个jar包,包名为cglib-nodep-2.2.jar。

    首先我们要创建CglibProxy的类,这个类实现MethodInteceptor接口

    public class CglibProxy implements MethodInterceptor{  
        @Override  
        public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {  
            // TODO Auto-generated method stub  
            //方法拦截前可以执行比如说权限检查之类的  
            arg3.invokeSuper(arg0, arg2);//代理类调用父类的方法  
            //方法拦截后可以执行比如说日志输出等等  
            return null;  
        }  
    }  

    测试方法如下:

     
    public class Test {  
        public static void main(String[] args) {  
            // TODO Auto-generated method stub  
            Car c=new Car();  
            CglibProxy cg=new CglibProxy();  
            Enhancer enhance=new Enhancer();//作用是创建一段动态地类字节码  
            enhance.setSuperclass(c.getClass());//设置父类,也就是使用传递过来的类来创建代理类  
            enhance.setCallback(cg);//这个回调函数就是把调用的方法改为CglibProxy中的inteceptor方法,并称此行为为增强目标类  
            Car c1=(Car)enhance.create();  
            c1.move();  
        }  
    }  
  • 相关阅读:
    touchWX 自定义组件以及传值
    VUE 中 使用 iview Form组件 enter键防止页面刷新
    记一次vue 普通异步请求微信二进制二维码 乱码 问题解决然后渲染
    数组黑科技(偏性能方面)未完待更新...
    判断字符串是否为JSON
    C#中的static、readonly与const的比较
    C#中的分部类和分部方法:partial
    C#中使用Log4Net记录日志
    C# 利用log4net 把日志写入到数据库表中
    RabbitMQ---5、qos内存溢出+prefetch消息堵塞问题
  • 原文地址:https://www.cnblogs.com/hunrry/p/9183068.html
Copyright © 2011-2022 走看看