设计模式——代理模式(静态代理和JDK、CGLib动态代理)
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了设计模式——代理模式(静态代理和JDK、CGLib动态代理),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4263字,纯文字阅读大概需要7分钟。
内容图文
简介
什么是代理模式?
代理模式就是多一个代理类出来,代替原对象进行一些操作。比如说租房的中介、打官司的律师、旅行社,他们可以代替我们做一些事情,这就是代理。
代理模式的应用场景:
如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法:
1. 修改原有的方法来做到改进。但这样违反了“对扩展开放,对修改关闭”的原则。
2. 采用一个代理类调用原有的方法,且对产生的结果进行控制。这就是代理模式。
代理模式的分类:
静态代理:由程序员创建代理类或特定工具自动生成源代码再对其编译。再程序运行前代理类的.class文件就已经存在了。
动态代理:在程序运行时用反射机制,动态创建代理类。
静态代理
所谓静态就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
package Proxy; //Created by zhengbinMac on 2017/2/19. public interface Hello { public void sayHello(String way); }
package Proxy; // Created by zhengbinMac on 2017/2/19. public class HelloImpl implements Hello{ publicvoid sayHello(String way) { System.out.println("Hello by " + way); } }
package Proxy; // Created by zhengbinMac on 2017/2/19. public class HelloProxy implements Hello { private Hello hello; public HelloProxy() { hello = new HelloImpl(); } privatevoid sayBefore() { System.out.println("Before.."); } privatevoid sayAfter() { System.out.println("After.."); } publicvoid sayHello(String way) { sayBefore(); hello.sayHello(way); sayAfter(); } }
代理类和委托类要实现相同的接口,因为代理真正调用的还是委托类的方法。HelloProxy 类实现了 Hello 接口,在构造方法中 new 出一个 HelloImpl 类的实例。在 sayHello()方法中调用 HelloImpl 的 sayHello()方法,同时在调用的前后加上 before 与 after 方法。
测试类:
package Proxy; // Created by zhengbinMac on 2017/2/19. public class Test { public static void main(String[] args) { Hello proxy = new HelloProxy(); proxy.sayHello("normal"); } }
输出结果:
Before..
Hello by normal
After..
以上就是静态代理,下面分析其带来的优缺点:
优点:
客户端不必知道实现类(委托类)如何如何,只需要调用代理类即可。
缺点:
- 代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。但这样出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也要实现这个方法。这显然增加了代码的复杂度。
- 代理对象只服务于一种类型的对象,如果要服务多类型的对象,那就要对每种对象都进行代理。静态代理子啊程序规模稍大是就无法胜任了。
JDK代理——接口级别代理
package Proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; // Created by zhengbinMac on 2017/2/19. public class DynamicProxy implements InvocationHandler{ private Object target; public DynamicProxy(Object target) { this.target = target; } @SuppressWarnings("unchecked") public <T> T getProxy() { return (T) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), this ); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { sayBefore(); Object result = method.invoke(target, args); sayAfter(); return result; } privatevoid sayBefore() { System.out.println("before..."); } privatevoid sayAfter() { System.out.println("after..."); } }
JDK 提供的 Proxy 类的工厂方法 newProxyInstance 去动态地创建一个 Hello 接口的代理类。
Proxy.newProxyInstance:
参数:
- loader - 定义代理类的类加载器
- interfaces - 代理类要实现的接口列表
- h - 指派方法调用的调用处理程序
返回:
一个带有代理类的指定调用处理程序的代理实例,它由指定类加载器定义,并实现指定的接口。
测试类:
package Proxy; // Created by zhengbinMac on 2017/2/19. public class Test { public static void main(String[] args) { DynamicProxy dynamicProxy = new DynamicProxy(new HelloImpl()); Hello hello = dynamicProxy.getProxy(); hello.sayHello("JDK"); } }
动态代理相比静态代理,接口变了,动态代理类不需要改变,而静态代理类不仅需要改变实现类,代理类也需要修改。
但如果要代理一个没有接口的类,JDK动态代理就用不上了,这就引出了CGLib代理。
CGLib代理——方法级别代理
Spring、Hibernate框架都是用了它,它是一个在运行期间动态生成字节码的工具,也就是动态生成代理类。
package Proxy; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; // Created by zhengbinMac on 2017/2/19. public class CGLibProxy implements MethodInterceptor { // 单例模式privatestatic CGLibProxy instance = new CGLibProxy(); private CGLibProxy() {} publicstatic CGLibProxy getInstance () { return instance; } public <T> T getProxy(Class<T> cls) { return (T) Enhancer.create(cls, this); } public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { sayBefore(); Object result = methodProxy.invokeSuper(obj, objects); sayAfter(); return result; } privatevoid sayBefore() { System.out.println("before..."); } privatevoid sayAfter() { System.out.println("after..."); } }
CGLib 给我们提供的是方法级别的代理,也可以理解为对方法的拦截。通过直接调用 proxy 的 invokeSuper 方法,将被代理的对象 obj 以及芳发的参数 objects 传入其中即可。
测试类:
package Proxy; // Created by zhengbinMac on 2017/2/19. public class Test { public static void main(String[] args) { Hello helloCGLib = CGLibProxy.getInstance().getProxy(HelloImpl.class); helloCGLib.sayHello("CGLib"); } }
原文:http://www.cnblogs.com/zhengbin/p/6514045.html
内容总结
以上是互联网集市为您收集整理的设计模式——代理模式(静态代理和JDK、CGLib动态代理)全部内容,希望文章能够帮你解决设计模式——代理模式(静态代理和JDK、CGLib动态代理)所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。