动态代理(jdk&cglib)的用法
什么是代理模式(Proxy)
定义:给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用
在代理模式中,是需要代理对象和目标对象实现同一个接口
为什么要用代理
最最最主要的原因就是,在不改变目标对象方法的情况下对方法进行增强,比如,我们希望对方法的调用增加日志记录,或者对方法的调用进行拦截,等等...
一:JDK动态代理
JDK动态代理所用到的代理类在程序调用到代理类对象时才由JVM真正创建,JVM根据传进来的 业务实现类对象 以及 方法名 ,动态地创建了一个代理类的class文件并被字节码引擎执行,然后通过该代理类对象进行方法调用。
案例
1、定义业务接口以及实现类
package com.yjc.jdkproxy; public interface DoSomeService { void doSome(); } ------------------------------------------- package com.yjc.jdkproxy; public class DoSomeServiceImpl implements DoSomeService { @Override public void doSome() { System.out.println("doSome++++++++++++++++++=="); } }
2.调用管理接口InvocationHandler 创建动态代理类
package com.yjc.jdkproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class DoSomeHandler implements InvocationHandler { //这其实业务实现类对象,用来调用具体的业务方法 private Object target; @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before----------------------------");
//调用真正的业务方法 Object invoke = method.invoke(target, args); System.out.println("after---------------------------"); return invoke; } public DoSomeHandler(Object target) { this.target = target;//接收业务实现类对象参数 } public DoSomeHandler() { } }
测试方法
package com.yjc.jdkproxy; import sun.misc.ProxyGenerator; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.lang.reflect.Proxy; public class JdkProxyTest { public static void main(String[] args) throws IOException { DoSomeService doSomeService=new DoSomeServiceImpl();
//通过反射机制,创建一个代理类对象实例并返回。用户进行方法调用时使用
//创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,在包装方法是调用真正的业务方法)、接口、handler实现类
DoSomeService o = (DoSomeService)Proxy.newProxyInstance(doSomeService.getClass().getClassLoader(), new Class[]{DoSomeService.class}, new DoSomeHandler(doSomeService)); //调用目标函数
o.doSome();
//将内存中代理的类生成到本地 byte[] $proxy0s = ProxyGenerator.generateProxyClass("$proxy0", new Class[]{DoSomeService.class}); FileOutputStream fos=new FileOutputStream("F:/$proxy0.class"); fos.write($proxy0s); fos.flush(); fos.close(); } }
二:CGLIB动态代理
cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理。
cglib和jdk动态代理的区别就是,cglib无需业务接口也可以实现动态代理,而jdk是在业务接口的基础上进行实现的,没有接口不行。cglib也需要项目对cglib的支持,需要引入依赖
业务类
package com.yjc.cglibproxy; public class DoSomeServiceImpl { public void doSome() { System.out.println("doSome++++++++++++++++++=="); } }
代理类
package com.yjc.cglibproxy; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class DoSomeHandler implements MethodInterceptor { //目标对象 private Object target; public DoSomeHandler(Object target) { this.target = target; } public DoSomeHandler() { }
/**
*
* 方法描述 当对基于代理的方法回调时,在调用原方法之前会调用该方法
* 拦截对目标方法的调用
*
* @param obj 代理对象
* @param method 拦截的方法
* @param args 拦截的方法的参数
* @param proxy 代理
* @return
* @throws Throwable
*/
@Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("before=========================="); Object invoke = method.invoke(target, objects); System.out.println("after============================"); return invoke; } }
测试类
package com.yjc.cglibproxy; import net.sf.cglib.proxy.Enhancer; public class CglibProxyTest { public static void main(String[] args) { Enhancer enhancer=new Enhancer();
// 设置目标对象的Class
enhancer.setSuperclass(DoSomeServiceImpl.class);
// 设置回调操作,相当于InvocationHandler
enhancer.setCallback(new DoSomeHandler(new DoSomeServiceImpl()));
DoSomeServiceImpl o =(DoSomeServiceImpl) enhancer.create();
o.doSome();
} }