深入拆解 Tomcat & Jetty
李号双
eBay 技术主管
38890 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 45 讲
开篇词 (1讲)
深入拆解 Tomcat & Jetty
15
15
1.0x
00:00/00:00
登录|注册

30 | 热点问题答疑(3):Spring框架中的设计模式

课后思考
代理模式
单例模式
工厂方法模式
简单工厂模式
Spring框架设计模式应用

该思维导图由 AI 生成,仅供参考

在构思这个专栏的时候,回想当时我是如何研究 Tomcat 和 Jetty 源码的,除了理解它们的实现之外,也从中学到了很多架构和设计的理念,其中很重要的就是对设计模式的运用,让我收获到不少经验。而且这些经验通过自己消化和吸收,是可以把它应用到实际工作中去的。
在专栏的热点问题答疑第三篇,我想跟你分享一些我对设计模式的理解。有关 Tomcat 和 Jetty 所运用的设计模式我在专栏里已经有所介绍,今天想跟你分享一下 Spring 框架里的设计模式。Spring 的核心功能是 IOC 容器以及 AOP 面向切面编程,同样也是很多 Web 后端工程师每天都要打交道的框架,相信你一定可以从中吸收到一些设计方面的精髓,帮助你提升设计能力。

简单工厂模式

我们来考虑这样一个场景:当 A 对象需要调用 B 对象的方法时,我们需要在 A 中 new 一个 B 的实例,我们把这种方式叫作硬编码耦合,它的缺点是一旦需求发生变化,比如需要使用 C 类来代替 B 时,就要改写 A 类的方法。假如应用中有 1000 个类以硬编码的方式耦合了 B,那改起来就费劲了。于是简单工厂模式就登场了,简单工厂模式又叫静态工厂方法,其实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类。
Spring 中的 BeanFactory 就是简单工厂模式的体现,BeanFactory 是 Spring IOC 容器中的一个核心接口,它的定义如下:
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Spring框架应用了多种设计模式,包括简单工厂模式、工厂方法模式、单例模式和代理模式。这些设计模式赋予Spring框架更好的灵活性、可维护性和扩展性,对于Web后端工程师提升设计能力和解决实际工作中的问题具有重要意义。在Spring中,简单工厂模式体现为BeanFactory,解决了硬编码耦合的问题;工厂方法模式体现为FactoryBean,提供更高的灵活性和复杂场景的应用;单例模式通过单例注册表的方式实现,使用HashMap保存单实例对象;代理模式在Spring中应用广泛,包括静态代理和动态代理两种方式,动态代理通过Proxy类和InvocationHandler接口实现,可以对类进行方法级别的切面增强,实现AOP。此外,文章还提到了JDK提供实现动态代理的机制以及通过CGLIB来实现的方式。读者还被鼓励思考newProxyInstance方法的实现方式,并与其他同学一起讨论。整体而言,本文深入浅出地介绍了Spring框架中的设计模式应用,对于想要深入了解Spring框架的读者具有很高的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入拆解 Tomcat & Jetty 》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(16)

  • 最新
  • 精选
  • neohope
    //在Proxy类里中: //constructorParams的定义如下: private static final Class<?>[] constructorParams = { InvocationHandler.class }; //newProxyInstance无限精简之后就是: public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { //通过ProxyClassFactory调用ProxyGenerator生成了代理类 Class<?> cl = getProxyClass0(loader, interfaces); //找到参数为InvocationHandler.class的构造函数 final Constructor<?> cons = cl.getConstructor(constructorParams); //创建代理类实例 return cons.newInstance(new Object[]{h}); } //在ProxyGenerator类中: public static byte[] generateProxyClass(final String name,Class<?>[] interfaces, int accessFlags)){} private byte[] generateClassFile() {} //上面两个方法,做的就是 //将接口全部进行代理 //并生成其他需要的方法,比如上面用到的构造函数、toString、equals、hashCode等 //生成对应的字节码 //其实这也就说明了,为何JDK的动态代理,必须需要至少一个接口

    作者回复: 👍

    2019-07-24
    14
  • nightmare
    老师能讲一下spring这么解决循环依耐的吗

    作者回复: Spring只解决了单例bean通过setXxx或者@Autowired进行循环依赖:https://blog.csdn.net/qq924862077/article/details/73926268 其他场景可以想办法绕过:https://www.baeldung.com/circular-dependencies-in-spring

    2019-07-19
    10
  • z.l
    老师 ,工厂方法模式没看懂。另外DefaultSingletonBeanRegistry的getBean方法的实现存在线程安全问题吧?虽然用了ConcurrentHashMap,但是if (singletonObject == null) 存在竞态条件, 可能有2个线程同时判断为true,最后产生了2个对象实例。应该用putIfAbsent方法。

    作者回复: 汗颜,代码简化的过程中去掉了线程安全的部分,线程安全的版本应该是这样的: //如果没拿到通过反射创建一个对象实例,并添加到HashMap中 if (singletonObject == null) { synchronized(singletonObjects){ if(singletonObjects.get(beanName) == null){ singletonObjects.put(beanName,Class.forName(beanName).newInstance()); } } }

    2019-07-18
    10
  • 802.11
    文中的工厂模式,有一个疑惑,它确实解决了对象的创建问题,但是对象每一个字段的赋值,工厂模式可以解决吗?或者怎么解决呢,谢谢

    作者回复: 字段赋初始值一般来说由类的构造函数或者初始化函数完成,但是Spring比较特殊,可以通过反射注入字段值

    2019-07-29
  • -W.LI-
    之前硬着头皮看过这个源码,中间有一步weakcache印象深刻。弱引用缓存,先从缓存中取,没取到获取字节码,校验魔术版本号之类的,最后反射实现。反射效率不高也是这个原因导致的,要获取源文件校验准备初始化(轻量级累加载一次)。
    2019-07-18
    12
  • QQ怪
    动态代理的思路便是动态生成一个新类,先通过传入的classLoader生成对应Class对象,后通过反射获取构造函数对象并生成代理类实例,jdk动态代理是通过接口实现的,但很多类是没有针对接口设计的,但是我们知道可以通过拼接字节码生成新的类的自由度是十分大的,所以cglib框架就是通过拼接字节码来实现非接口类的代理。
    2019-07-18
    6
  • QQ怪
    老师这次加餐面试必问题
    2019-07-18
    4
  • 草戊
    BeanFactory和FactoryBean的代码示例是一样的?
    2019-07-29
    1
    3
  • 靠人品去赢
    这个工厂模式,这各其实实例化的出来我觉得还是工厂bean,但是可以通过getObject来获取bean。这里可以看一下Spring的ObjectFactoryCreatingFactoryBean(通过继承AbstractFactoryBean ,然后由AbstractFactoryBean实现BeanFactory的) public Object getObject() throws BeansException { return this.beanFactory.getBean(this.targetBeanName); } 对应类名字传过来即可,若果是动态那工厂模式就大显神威了。
    2019-11-07
    1
  • 桔子
    谢谢,我学会了动态代理~
    2019-09-29
    1
收起评论
显示
设置
留言
16
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部