浅谈Java代理二:Cglib动态代理-MethodInterceptor
CGLib动态代理特点:
使用CGLib实现动态代理,完全不受代理类必须实现接口的限制,而且CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。
示例业务逻辑:
1-有一个明星叫胡歌(class HuGe)
3-找明星做事情需要经过助理(ProxyFactory )
4-如果要找胡歌唱歌、演戏,需要先找助理,然后助理去找胡歌唱歌、演戏(class testProcyFactory)
1-被代理类(没有实现任何接口)
package com.huishe.testOfSpring.methodinterceptor; public class HuGe { public void sing(String song) { System.out.println("胡歌演唱: " + song); } public String act(String teleplay) { System.out.println("胡歌决定出演电视剧: " + teleplay); return "胡歌答应出演电视剧: " + teleplay; } }
2-代理工厂(即创建代理的通用写法)
package com.huishe.testOfSpring.methodinterceptor; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class ProxyFactory implements MethodInterceptor{ //要代理的原始对象 private Object object; //1-创建代理对象 public Object createProcy(Object target){ this.object = target; //1-Enhancer类是CGLib中的一个字节码增强器,它可以方便的对你想要处理的类进行扩展 Enhancer enhancer=new Enhancer(); //2-将被代理类HuGe设置成父类 enhancer.setSuperclass(this.object.getClass()); //3-设置拦截器 enhancer.setCallback(this); //4-动态生成一个代理类 Object objProxy = enhancer.create(); return objProxy; } //2-实现MethodInterceptor的intercept方法 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("before: " + method); //调用proxy.invoke()方法,会报java.lang.StackOverflowError错误,原因是invoke()内部会一直被反复调用 //Object object = proxy.invoke(obj, args); Object object = proxy.invokeSuper(obj, args); System.out.println("after: " + method); return object; } }
3-进行测试
package com.huishe.testOfSpring.methodinterceptor; import org.junit.Test; import net.sf.cglib.proxy.Enhancer; public class cglibMethodInterceptorTest { @Test public void testProcyFactory(){ //1-实例化需要被代理的类 HuGe huGe = new HuGe(); //2-实例化代理工厂 ProxyFactory cglibProxy = new ProxyFactory(); //3-动态生成一个代理类,并从Object强制转型成父类型HuGe HuGe hg =(HuGe)cglibProxy.createProcy(huGe); //4-执行动态代理类的方法 hg.sing("逍遥叹"); hg.act("琅琊榜"); } }
4-测试结果
日志输出: before: public void com.huishe.testOfSpring.methodinterceptor.HuGe.sing(java.lang.String) 胡歌演唱: 逍遥叹 after: public void com.huishe.testOfSpring.methodinterceptor.HuGe.sing(java.lang.String) before: public java.lang.String com.huishe.testOfSpring.methodinterceptor.HuGe.act(java.lang.String) 胡歌决定出演电视剧: 琅琊榜 after: public java.lang.String com.huishe.testOfSpring.methodinterceptor.HuGe.act(java.lang.String)
参考资料
1-https://blog.csdn.net/jiaotuwoaini/article/details/51675684
2-https://www.cnblogs.com/writeLessDoMore/p/6973853.html