实现动态代理的两种方式
常见的实现代理的两种方式:(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 }
测试方法如下
这里解释一下很多人不理解为什么jdk动态代理的对象必须实现一个统一的接口,其实我的理解大致是代理类本身已经extends了TimeHandler,如果传入的是父类,很可能出现这种情况:
这个明显在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(); } }