内容简介:设计模式之动态代理
一、动态代理概念
动态代理分为JDK动态代理和cglib动态代理两种方式。JDK动态代理是由 Java 内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。
总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。
还有一点必须注意: JDK动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,JDK动态代理不能应用。
由此可以看出,JDK动态代理有一定的局限性,cglib这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。
二、JDK动态代理
以下代码使用代理模式实现一个大小写字符转换的功能。
定义接口和实现类:
ISomeService接口:
package com.ietree.basicskill.designpattern.dynamicproxy.jdk; /** * 接口类 * * @author Root */ public interface ISomeService { String doFirst(); void doSecond(); }
SomeServiceImpl实现类:
package com.ietree.basicskill.designpattern.dynamicproxy.jdk; /** * 实现类 * * @author Root */ public class SomeServiceImpl implements ISomeService { @Override public String doFirst() { System.out.println("执行doFirst()..."); String result = "abcde"; return result; } @Override public void doSecond() { System.out.println("执行doSecond()..."); } }
JDK动态代理类:
package com.ietree.basicskill.designpattern.dynamicproxy.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class Main { public static void main(String[] args) { final ISomeService target = new SomeServiceImpl(); // 使用JDK的Proxy动态代理,要求目标类和代理类必须实现相同的接口,因为其底层的执行原理与静态代理的相同 ISomeService service = (ISomeService) Proxy.newProxyInstance( // 目标类的类加载器 target.getClass().getClassLoader(), // 目标类所实现的所有接口 target.getClass().getInterfaces(), new InvocationHandler() { // proxy:代理对象 // method:目标方法 // args:目标方法的参数列表 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 调用目标方法 Object result = method.invoke(target, args); if (result != null) { result = ((String) result).toUpperCase(); } return result; } }); String result = service.doFirst(); System.out.println(result); service.doSecond(); } }
三、cglib动态代理
Cglib是一个优秀的动态代理框架,它的底层使用ASM在内存中动态的生成被代理类的子类,使用CGLIB即使代理类没有实现任何接口也可以实现动态代理功能。CGLIB具有简单易用,它的运行速度要远远快于JDK的Proxy动态代理:
CGLIB的核心类:
net.sf.cglib.proxy.Enhancer – 主要的增强类
net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户实现
net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用,如使用:
Object o = methodProxy.invokeSuper(proxy, args);//虽然第一个参数是被代理对象,也不会出现死循环的问题。
net.sf.cglib.proxy.MethodInterceptor接口是最通用的回调(callback)类型,它经常被基于代理的AOP用来实现拦截(intercept)方法的调用。这个接口只定义了一个方法
public Object intercept(Object object, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable;
第一个参数是代理对像,第二和第三个参数分别是拦截的方法和方法的参数。原来的方法可能通过使用java.lang.reflect.Method对象的一般反射调用,或者使用 net.sf.cglib.proxy.MethodProxy对象调用。net.sf.cglib.proxy.MethodProxy通常被首选使用,因为它更快。
以下程序实现了大小写转换的功能:
实现类SomeService:
package com.ietree.basicskill.designpattern.dynamicproxy.cglib; /** * 实现类 * * @author Root */ public class SomeService { public String doFirst() { System.out.println("执行doFirst()..."); String result = "abcde"; return result; } public void doSecond() { System.out.println("执行doSecond()..."); } }
代理类MyCglibFactory:
package com.ietree.basicskill.designpattern.dynamicproxy.cglib; 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 MyCglibFactory implements MethodInterceptor { private SomeService target; public MyCglibFactory() { super(); target = new SomeService(); } public SomeService myCglibCreator() { // 创建增强器对象 Enhancer enhancer = new Enhancer(); // 指定目标类,即父类 enhancer.setSuperclass(SomeService.class); // 设置回调接口对象 enhancer.setCallback(this); return (SomeService) enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // 调用目标方法 Object result = method.invoke(target, args); if (result != null) { result = ((String) result).toUpperCase(); } return result; } }
测试:
package com.ietree.basicskill.designpattern.dynamicproxy.cglib; public class Main { public static void main(String[] args) { SomeService service = new MyCglibFactory().myCglibCreator(); String result = service.doFirst(); System.out.println("result = " + result); service.doSecond(); } }
运行结果:
执行doFirst()... result = ABCDE 执行doSecond()...
本文永久更新链接地址 : http://www.linuxidc.com/Linux/2017-06/144642.htm
以上所述就是小编给大家介绍的《设计模式之动态代理》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 设计模式——订阅模式(观察者模式)
- 设计模式-简单工厂、工厂方法模式、抽象工厂模式
- java23种设计模式-门面模式(外观模式)
- 设计模式-享元设计模式
- Java 设计模式之工厂方法模式与抽象工厂模式
- JAVA设计模式之模板方法模式和建造者模式
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。