设计模式已经跟大家分享很多了常见的模式了,感兴趣的小伙伴可以再回顾一下,巩固一下理解。
这次要跟大家分享的是设计模式中三大类创建型中的代理模式,代理模式在业务场景上我们可能不会经常用到,但是面试官却会经常问一个问题?
请你跟我讲讲Spring里面AOP的代理模式?jdk的代理模式和cglib的代理模式又啥区别?
清楚和不清楚的同学都可以接着向下看,一定会有收获。
言归正传,接下来开始一步一步分析一下代理模式。
首先代理模式可以分为多种类型
上面只是我们作为了解的概念,接下来再看看代理模式有哪些部分构成。
从图中可以看出其实整个接口还是很简单,就是一个真实对象以及代理对象。
为了方便理解,还是举一个例子,不知道大家在读初中或者高中是否经历过传小纸条的过程,假如现在同学A 对同学C有一些话想聊(比如放学相约一起打游戏)但是因为现在是上课时间,又不能大声说,同学A和同学C之间坐了一个同学B,所以现在同学A只能是先找到同学B把纸条给它,让他转告同学C,但是去玩还是不是不去玩,那还是只能真正的同学C自己才能决定。
所以代理模式可以理解为 同学B是同学的C的代理,同学A要找同学C,只能找到同学B,通过同学B转达同学C,同时将同学的C的执行结果反馈给同学A。
说完了例子还是具体看看代码的实现吧
- public interface Subject {
- // 共同的接口
- void doSomething();
- }
定义一个共同的接口(即大家要做的事请:放学一起打游戏)
- public class RealSubject implements Subject {
- // 真实对象
- @Override
- public void doSomething() {
- System.out.println("放学去打游戏");
- }
- }
构建一个真实对象,即例子中的同学C
- public class ProxySubject implements Subject {
- private RealSubject realSubject;
- public ProxySubject(RealSubject realSubject) {
- this.realSubject = realSubject;
- }
- public ProxySubject() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
- this.realSubject = (RealSubject) this.getClass().getClassLoader().loadClass("com.ao.bing.demo.proxyPattern.RealSubject").newInstance();
- }
- @Override
- public void doSomething() {
- realSubject.doSomething();
- }
- public static void main(String[] args) {
- try {
- // 第一种方式
- new ProxySubject().doSomething();
- // 打印结果: 放学去打游戏
- } catch (Exception e) {
- // 异常情况,代理失败,
- // 传纸条的被老师抓了。或者同学C不在座位上了 等异常情况
- }
- // 第二种方式
- new ProxySubject(new RealSubject()).doSomething();
- // 打印结果: 放学去打游戏
- }
- }
构建代理对象,即同学B,那么可以看到同学A并没有真实接触到同学C,通过同学B对同学C的代理就能知道同学C放学能不能跟他一起去打游戏
在Main方法里面,有两种方式来调用真实对象
这里大家要区别一下,代理模式是提供完全相同的接口,而装饰器模式是为了增强接口。
在上面的举的列子实现其实就是静态代理,大家可以看到整体也比较简单。但是它的缺点也很明显
静态代理需要为每一个对象都创建一个代理类,增加了维护成本以及开发成本,那么为了解决这个问题,动态代理就出来了,不要再固定为每一个需要代理的类而创建一个代理类
动态代理合理的避免了静态代理的那种方式,不用事先为要代理的类而构建好代理类。而是在运行时通过反射机制创建。
在写动态代理事需要理解两个东西:Proxy 可以理解为就是调度器,InvocationHandler 增强服务接口可以理解为代理器。所以我个人理解动态代理其实就是一种行为的监听。
具体的代码实现举一个例子:螳螂捕蝉,通过通过螳螂监听到蝉的动作。方便后面讲到多级代理模式。
- public interface BaseService {
- void mainService();
- }
- public class Cicada implements BaseService {
- @Override
- public void mainService() {
- System.out.println("主要业务,以蝉为例,当蝉出现业务调用时,螳螂监听到");
- }
- }
创建共同接口,以及真实对象蝉
- public class PrayingMantis implements InvocationHandler {
- private BaseService baseService;
- // 这里采用的是构建传参数,可以用反射,举的第一个例子有样式代码
- public PrayingMantis(BaseService baseService) {
- this.baseService = baseService;
- }
- // 螳螂主要业务,也就是监听对象
- @Override
- public Object invoke(Object listener, Method method, Object[] args) throws Throwable {
- method.invoke(baseService,args);
- secondaryMain();
- return null;
- }
- // 这里理解增强业务,即我们可以在实现InvocationHandler里面添加其他的业务,比如日志等等。
- private void secondaryMain(){
- System.out.println("螳螂捕蝉 - 次要业务");
- }
- }
创建螳螂类,监听着蝉的类的动作
- public class BeanFactory {
- public static BaseService newInstanc(Class classFile) {
- // 1. 创建蝉,真实类对象
- BaseService trueCicada = new Cicada();
- // 2.创建代理类 螳螂
- InvocationHandler prayingMantis = new PrayingMantis(trueCicada);
- // 3.向Jvm索要代理对象 其实就是监听的对象,
- Class classArray[] = {BaseService.class};
- BaseService baseService = (BaseService) Proxy.newProxyInstance(classFile.getClassLoader(), classArray, prayingMantis);
- return baseService;
- }
- // 测试Demo
- public static void main(String[] args) {
- BaseService baseService = newInstanc(Cicada.class);
- baseService.mainService();
- // 测试结果 :主要业务
- // 螳螂捕蝉 - 次要业务
- }
- }
通过结果可以看出当蝉主要业务发生调用时,螳螂能监听到蝉的业务并且能处理其他业务逻辑,这也就是Spring里面AOP为什么能处理日志切面等。
代理的本质:
代理模式组成:
其实和jdk的动态代理是很相似的,都是要去实现代理器接口完成。
具体代码如下:
- public class PrayingMantis implements MethodInterceptor {
- private Cicada cicada;// 代理对象
- public Cicada getInstance(Cicada cicada) {
- this.cicada = cicada;
- Enhancer enhancer = new Enhancer();
- enhancer.setSuperclass(this.cicada.getClass());
- enhancer.setCallback(this);
- return (Cicada) enhancer.create();
- }
- @Override
- public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
- Object object = methodProxy.invokeSuper(o, objects);
- secondaryMain();
- return object;
- }
- private void secondaryMain() {
- System.out.println("螳螂捕蝉 - 次要业务");
- }
- public static void main(String[] args) {
- PrayingMantis prayingMantis = new PrayingMantis();
- Cicada instance = prayingMantis.getInstance(new Cicada());
- instance.mainService();
- // 结果:主要业务
- // 螳螂捕蝉 - 次要业务
- }
因为蝉类都是一样的所以我就不单独这里再贴出来。
细心的同学已经发现,Cglib 无需通过接口来实现,它是通过实现子类的方式来完成调用的。
JDK和Cglib的区别:
看完上面的动态代理,不知道大家有没有想法,实现一个多级动态代理。
还是以螳螂捕蝉为例子,再加上一个黄雀在后,实现多级动态代理模式。
- public class Cardinal implements InvocationHandler {
- // 监听代理代理对象
- private Object proxyOne;
- public Cardinal(Object proxyOne) {
- this.proxyOne = proxyOne;
- }
- // 螳螂主要业务,也就是监听对象
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- method.invoke(proxyOne, args);
- secondaryMain();
- return null;
- }
- private void secondaryMain() {
- System.out.println("黄雀吃螳螂 - 次要业务");
- }
- }
创建一个黄雀代理对象,那作为他的真实对象就变成螳螂了,当螳螂对象发生调用时,黄雀就能坚挺到,同时作出对应业务逻辑
- public class BeanFactory {
- public static BaseService newInstanc(Class classFile) {
- // 1. 创建蝉,真实类对象
- BaseService trueCicada = new Cicada();
- // 2.创建代理类 螳螂
- InvocationHandler prayingMantis = new PrayingMantis(trueCicada);
- // 3.向Jvm索要代理对象 其实就是坚挺的对象
- Class classArray[] = {BaseService.class};
- BaseService baseService = (BaseService) Proxy.newProxyInstance(classFile.getClassLoader(), classArray, prayingMantis);
- // 4.创建代理实现类 黄雀 二级代理
- InvocationHandler cardinal = new Cardinal(baseService);
- BaseService secondBaseService = (BaseService) Proxy.newProxyInstance(classFile.getClassLoader(), classArray, cardinal);
- // 假设要实现三级,四级代理,则在黄雀类上再加一层代理即可实现。
- // 省略其他的更多级代理对象
- return secondBaseService;
- }
- // 测试demo
- public static void main(String[] args) {
- BaseService baseService = BeanFactory.newInstanc(Cicada.class);
- baseService.mainService();
- // 结果:主要业务
- // 螳螂捕蝉 - 次要业务
- // 黄雀吃螳螂 - 次要业务
- }
- }
根据这个代码基本就实现多级代理过程。螳螂监听着蝉类的动作,黄雀监听着螳螂类的动作。
同样的如果要实现三级代理,四级代理也就不是什么难事了,在每一层的上面再加一个代理对象就可以了。
代理模式在业务代码上我个人认为是比较少见的,特别是动态代理基本上是没有见过。但是代理模式也是我们必须要理解的一种模式,因为学习好代理模式有助于我们去读一些源码,排查一些更深层次的问题,或者面对一些业务场景问题,也能有一个很大的提升,设计模式本身也就是为了解决问题而创建出来的。
理解完动态代理现在对我们来说AOP的实现原理也就不言而喻了。
详细的设计模式到这里就结束了,后面针对一些不常见设计模式我还是会给大家做一个总结吧。
我是敖丙,你知道的越多,你不知道的越多,我们下期见!!!
新闻标题:详解设计模式之代理模式
标题来源:http://www.csdahua.cn/qtweb/news35/390985.html
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网