面试官问你设计模式 你还在回答单例 和 工厂 ( 代理模式了解一下)

面试官问你设计模式 你还在回答单例 和 工厂 ? 代理模式了解一下 走过路过不要错过,上一篇讲了反射,可以看我上一篇文章或微信上搜索:木子的昼夜编程 。
这一篇准备写一下动态代理模式。
1. 理由 先给你一个理由,为什么学动态代理
第一他是一种设计模式,在你工作中如果可以结合它的使用,那代码绝对漂亮。
第二面试官们喜欢问的面试题就包括设计模式,如果掌握这种设计模式,那你下一份工作的薪水可能就会高一点点。
第三你可能看过很多源码包括但不限于Mybatis、Spring ,他们的作者在编写代码的时候就充分利用了动态代理的思想,你掌握了这个技术之后,就能很好的理解那些写框架的大佬们是怎么设计的框架,从而得到能力的提升。
2. 动起来 2.1 先说代理 代理就是一个类代表另一个类提供功能,你可以理解成你朋友圈的微商。
厂商生产鞋子->微商从厂商那里批发鞋子在朋友圈进行售卖->你购买鞋子
微商就是代理,代理的就是鞋子厂商,而你就是那个使用鞋子厂商生产的鞋子但是你需要与微商打交道。
网上经常会看到一个UML图,在下也献丑画一个。
面试官问你设计模式 你还在回答单例 和 工厂 ( 代理模式了解一下)
文章图片

2.2 代理的优缺点 优点:我的总结就是高扩展、智能化、职责清晰
缺点:成本加大(你购买的鞋子可能变贵,运输时间可能变长)
3. 先静再动 聊动态代理之前先写一个静态代理的例子。

package test; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 一个生活在互联网底层,做着增删改查的码农,不谙世事的造作 * @create 2021-10-16 9:39 * * 鞋厂规范 */ public interface AShoeFactory { /** * * @param name 购鞋者名字 * @param num 购买鞋子数量 */ void sellingShoes(String name, Integer num); }

package test; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 一个生活在互联网底层,做着增删改查的码农,不谙世事的造作 * @create 2021-10-16 9:44 * * 具体的鞋厂:鸿星尔克 */ public class ErkeFactory implements AShoeFactory{@Override public void sellingShoes(String name, Integer num) { System.out.println(name+" 购买了 "+ num+" 双鞋,放烟花庆祝!!"); } }

package test; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 代理类:朋友圈某某某 */ public class ProxyWechatMoments implements AShoeFactory{ public ProxyWechatMoments(){}public ProxyWechatMoments(ErkeFactory erkeFactory){ this.erkeFactory = erkeFactory; } ErkeFactory erkeFactory; @Override public void sellingShoes(String name, Integer num) { erkeFactory.sellingShoes(name, num); } }

测试:
import test.ErkeFactory; import test.ProxyWechatMoments; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 */ public class Test { public static void main(String[] args) { // 真实提供能力的类 ErkeFactory erkeFactory = new ErkeFactory(); // 代理类 ProxyWechatMoments proxy =new ProxyWechatMoments(erkeFactory); // 冲动消费 proxy.sellingShoes("最最最最最小李子", 10); } }

测试输出结果:
最最最最最小李子 购买了 10 双鞋,放烟花庆祝!!
4. 动起来 写了静态代理,静态代理实现比较简单。
缺点呢:扩展比较麻烦,如果上述例子中再加一个匹克鞋厂,我们就需要修改代码,会在代理类中用if else区分要购买哪个牌子的鞋、
4.1 动态代理之 JDK
package test; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 动态代理类 */ public class ProxyDynamicHandler implements InvocationHandler { privateAShoeFactory shoeFactory; public ProxyDynamicHandler(){} public ProxyDynamicHandler(AShoeFactory shoeFactory) { this.shoeFactory = shoeFactory; }@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 卖鞋前后做的事情 是代理模式中经常用到的功能,作为增强和过滤使用 System.out.println("动态代理的好处,卖鞋前做一些事情"); String name = (String)args[0]; // 如果购买的人是 追忆流年时光 那我就不卖给他 if ("追忆流年时光".equals(name)) { System.out.println("不卖, 谢谢 !"); } else { // 这里用到了反射 没掌握的人可以看我上一篇文章 或关注公众号:木子的昼夜编程 method.invoke(shoeFactory, args); } System.out.println("动态代理的好处,卖鞋后做一些事情"); return null; } }

import sun.applet.AppletClassLoader; import test.AShoeFactory; import test.ErkeFactory; import test.ProxyDynamicHandler; import java.lang.reflect.Proxy; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 */ public class TestDynamic { public static void main(String[] args) { AShoeFactory factory = (AShoeFactory) Proxy.newProxyInstance( ErkeFactory.class.getClassLoader(),// 类加载器 ErkeFactory.class.getInterfaces(),// 代理的类的所有接口 Jdk动态代理是基于接口的 // 如果学过Spring的动态代理的话应该知道,默认如果你的Service有接口Spring会使用Jdk动态代理 // 如果你的Service没有接口 Spring会使用CGLIB // 这个知识 是我记忆中的 对不对不负责 哈哈 new ProxyDynamicHandler(new ErkeFactory())); factory.sellingShoes("正义的帅哥", 10); System.out.println("-------------------华丽丽的分割线------------------------"); factory.sellingShoes("追忆流年时光", 10); } }

输出:
动态代理的好处,卖鞋前做一些事情
正义的帅哥 购买了 10 双鞋,放烟花庆祝!!
动态代理的好处,卖鞋后做一些事情
-------------------华丽丽的分割线------------------------
动态代理的好处,卖鞋前做一些事情
不卖, 谢谢 !
动态代理的好处,卖鞋后做一些事情
4.2 CGLIB 动态代理 CGLIB 是一个很牛X的代码生成库,常被用在一些AOP框架里。
CGLIB底层使用了ASM来操作字节码
他是对字节码进行了操作,说实话不是很安全,但是用起来很爽。
就是没有约束的技术最疯狂。
CGLIB实现动态代理的方式就是认干爹,利用字节码修改功能创建一个被代理类(匹克鞋厂)的子类,提供功能的时候还是使用了被代理类的功能,就跟花钱找干爹一个道理
注: 这里的干爹是那种,70年代 80年代 很纯粹的那种两家关系好 就认干爹那种 不是现代意思。
pom.xml
cglib cglib 3.3.0

package test; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 */ public class PeakFactory { public void sellingShoes(String name, Integer num) { System.out.println(name+" 购买了 "+ num+" 双匹克鞋,放烟花庆祝!!"); } }

自定义MethodHandler:
package test; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 */ public class ProxyDynamicByCglib implements MethodInterceptor {@Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // 卖鞋前后做的事情 是代理模式中经常用到的功能,作为增强和过滤使用 System.out.println("动态代理的好处,卖鞋前做一些事情"); String name = (String)args[0]; // 如果购买的人是 追忆流年时光 那我就不卖给他 if ("追忆流年时光".equals(name)) { System.out.println("不卖, 谢谢 !"); } else { System.out.println("看一下代理对象的父类是个啥:"+obj.getClass().getSuperclass()); // 调用业务类(父类)的方法 proxy.invokeSuper(obj, args); } System.out.println("动态代理的好处,卖鞋后做一些事情"); // 本次测试没有返回 无需返回 return null; } }

测试:
import net.sf.cglib.proxy.Enhancer; import test.*; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 */ public class TestDynamicCGLIB { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); // 重点 设置实际提供方法的类为父类 Cglib使用自己的修改字节码功能 生成一个这个类的子类对象 enhancer.setSuperclass(PeakFactory.class); enhancer.setCallback(new ProxyDynamicByCglib()); // 自定义的Intrceptor PeakFactory factory = (PeakFactory) enhancer.create(); factory.sellingShoes("正义的帅哥", 10); System.out.println("-------------------华丽丽的分割线------------------------"); factory.sellingShoes("追忆流年时光", 10); } }

输出:
动态代理的好处,卖鞋前做一些事情
看一下代理对象的父类是个啥:class test.PeakFactory
正义的帅哥 购买了 10 双匹克鞋,放烟花庆祝!!
动态代理的好处,卖鞋后做一些事情
-------------------华丽丽的分割线------------------------
动态代理的好处,卖鞋前做一些事情
不卖, 谢谢 !
动态代理的好处,卖鞋后做一些事情
5. 唠唠 代理的话我对JDK动态代理和CGLIB动态代理的底层了解不是很好,所以就只展开说了一下简单的应用。
【面试官问你设计模式 你还在回答单例 和 工厂 ( 代理模式了解一下)】其实大部分时候看架构源码,很多地方会用到代理模式,根据我的经验,会简单使用的就可以看懂架构中的代码流程,不用探索太深,当然不是不鼓励你去探索,知识说如果有时间的话再去探索,没时间就先学会怎么用。
本文由博客一文多发平台 OpenWrite 发布!

    推荐阅读