Spring Boot源码中设计模式应用浅析

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 背景:大家好,我是冰点。最近有网友反馈,他在面试过程中被面试官问到,设计模式,他按自己背设计模式的八股文回答了,之后面试官又追问了一句,那你知道 你们项目所用的spring boot都使用了哪些设计模式呢,这些设计模式是怎么应用的呢?。我这位网友,说自己直接懵逼,瞬间感觉之前背的设计模式八股文,一文不值哈哈。那今天我们分析一下Spring Boot 源码中的设计模式应用。工欲善其事必先利其器。加油。

1. 工厂模式

8a62985a1e5f4d62a3751f9d11263d4f.png

在 Spring Boot 中,工厂模式主要体现在 BeanFactory 和 ApplicationContext 接口的实现上。BeanFactory 是 Spring 中最基本的工厂模式实现,它负责创建和管理 Bean 对象。ApplicationContext 是 BeanFactory 的一个子接口,它增加了许多企业级的特性,如国际化、事件传递、AOP 等。ApplicationContext 的实现类包括 ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、AnnotationConfigApplicationContext 等。

我们通常使用注解(如 @Component、@Service、@Repository 等)来标记需要创建的对象,Spring 容器会根据这些注解来创建对象并管理它们的生命周期。具体实现可以参考 Spring Framework 的 BeanFactory 和 ApplicationContext 接口。

1.1 详解 DefaultListableBeanFactory

DefaultListableBeanFactory 是 Spring Framework 中的工厂模式的实现之一,它是 BeanFactory 接口的默认实现类。它负责创建和管理 Bean 对象,并提供了许多与 Bean 相关的操作,如 Bean 的注册、依赖注入、生命周期管理等。


DefaultListableBeanFactory 通过解析 XML 配置文件或者注解来创建 Bean 对象,并将其缓存在一个 Map 中,当需要获取 Bean 对象时,通过 getObjectForBeanInstance() 方法来获取对应 Bean 的实例对象。如果缓存中不存在该 Bean 的实例对象,则通过 createBean() 方法来创建一个新的实例对象并放入缓存中。

DefaultListableBeanFactory 是 Spring Framework 中的一个核心类,它实现了 BeanFactory 接口,并提供了创建、管理、销毁 Bean 对象的功能。下面我们来逐步解析 DefaultListableBeanFactory 的源码。


首先,我们来看一下 DefaultListableBeanFactory 的类定义:

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
    implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    // ...
}

可以看到,DefaultListableBeanFactory 继承了

AbstractAutowireCapableBeanFactory,并实现了

ConfigurableListableBeanFactory、BeanDefinitionRegistry 和 Serializable

接口。其中,AbstractAutowireCapableBeanFactory 提供了 Bean

自动装配的功能,ConfigurableListableBeanFactory 定义了可配置的 ListableBeanFactory

接口,BeanDefinitionRegistry 定义了 BeanDefinition 的注册接口,而 Serializable

则是为了支持对象序列化。


接下来,我们来看一下 DefaultListableBeanFactory 中的一些重要属性:

@Nullable
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
private final List<String> beanDefinitionNames = new ArrayList<>(256以上是 DefaultListableBeanFactory 中的一些重要属性,其中:

beanClassLoader:Bean 的类加载器,默认为 ClassUtils.getDefaultClassLoader(),即当前线程的上下文类加载器。

beanDefinitionMap:BeanDefinition 对象的缓存,key 为 Bean 的名称,value 为 BeanDefinition 对象。

beanDefinitionNames:Bean 的名称列表,用于快速遍历。

接下来我们来看一下 DefaultListableBeanFactory 中的一些重要方法:

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
public void removeBeanDefinition(String beanName)
public BeanDefinition getBeanDefinition(String beanName)
public boolean containsBeanDefinition(String beanName)
public String[] getBeanDefinitionNames()
public int getBeanDefinitionCount()
public boolean isBeanNameInUse(String beanName)

可以看到,这些方法主要用于 BeanDefinition 对象的注册、查询、删除和遍历操作。

接下来,我们来看一下 DefaultListableBeanFactory 中的一些重要方法:

public Object getBean(String name)
public <T> T getBean(String name, Class<T> requiredType)
public <T> T getBean(Class<T> requiredType)
public Object getBean(String name, Object... args)
public <T> T getBean(Class<T> requiredType,Object... args)

这些方法是 DefaultListableBeanFactory 中最核心的方法,它们用于获取 Bean 对象。其中,getBean() 方法是最常用的方法,它可以根据 Bean 的名称或类型来获取对应的 Bean 实例对象。具体来说,getBean()方法会先从缓存中查找对应的 Bean 实例对象,如果缓存中不存在,则通过 createBean() 方法来创建一个新的 Bean实例对象,并将其放入缓存中。


除了上述方法之外,DefaultListableBeanFactory 还提供了许多其他的方法和接口,用于处理 Bean 的生命周期、作用域、AOP 等方面的功能。例如,DefaultListableBeanFactory 中提供了以下方法:

public void destroySingletons()
public void registerSingleton(String name, Object singletonObject)
public Object getSingleton(String beanName)
public boolean containsSingleton(String beanName)
public int getSingletonCount()

这些方法主要用于管理单例对象的生命周期,包括单例对象的创建、销毁和缓存等操作。

最后,我们来看一下 DefaultListableBeanFactory 中 createBean() 方法的源码,该方法用于创建 Bean 实例对象。

protectedObject createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    // Resolve before instantiating the bean to allow for short-circuits.
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    final Object bean = instanceWrapper.getWrappedInstance();
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }
    // Allow post-processors to modify the merged bean definition.
    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            mbd.postProcessed = true;
        }
    }
    // Eagerly cache singletons to be able to resolve circular references
    // even when triggered by lifecycle interfaces like BeanFactoryAware.
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
            isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        if (logger.isDebugEnabled()) {
            logger.debug("Eagerly caching bean '" + beanName +
                    "' to allow for resolving很好,接下来我们继续解析 createBean() 方法的源码。
// Initialize the bean instance.
Object exposedObject = bean;
try {
    populateBean(beanName, mbd, instanceWrapper);
    if (exposedObject != null) {
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
} catch (Throwable ex) {
    if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
        throw (BeanCreationException) ex;
    } else {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
    }
}
if (earlySingletonExposure) {
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, exposedObject));
    singletonObjects.remove(beanName);
    earlySingletonObjects.remove(beanName);
    registeredSingletons.add(beanName);
}
return exposedObject;

可以看到,createBean() 方法主要分为以下几个步骤:


创建 Bean 实例对象,并将其封装为 BeanWrapper 对象。如果 Bean 是单例对象,则从 factoryBeanInstanceCache 缓存中获取,否则通过 createBeanInstance() 方法来创建一个新的实例对象。

应用 MergedBeanDefinitionPostProcessor 对象到 Bean 上,以修改其 BeanDefinition 属性值和 Bean 实例对象。

初始化 Bean 实例对象,包括属性注入、初始化方法调用等操作。如果 Bean 是单例对象,则在初始化前进行缓存操作,以便后续解决循环依赖等问题。

如果 Bean 是单例对象,并且需要提前暴露,则将其缓存到 singletonFactories 中,并从 singletonObjects 和 earlySingletonObjects 缓存中移除。

返回 Bean 实例对象。

DefaultListableBeanFactory 的源码比较庞大,涉及的功能也比较复杂,需要结合具体的使用场景和实现细节来进行深入理解和分析。不过,通过对DefaultListableBeanFactory 的源码解析,我们可以更好地理解 Spring Framework 中的BeanFactory 设计模式,并从中获得一些启发和思考。

2. 单例模式

在 Spring Boot 中,单例模式主要体现在 Bean 的创建和管理上。默认情况下,Spring 容器会将 Bean 创建为单例对象,并在整个应用程序生命周期中保持唯一。这种单例模式的实现方式可以避免多线程竞争和资源浪费,同时也方便了对象的管理和维护。


在 Spring Boot 中,单例模式的实现可以参考 Spring Framework 的 DefaultSingletonBeanRegistry 接口。这个类维护了一个单例对象的缓存,通过 getObjectForBeanInstance() 方法来获取对应 Bean 的实例对象,如果缓存中不存在该 Bean 的实例对象,则通过 createBean() 方法来创建一个新的实例对象并放入缓存中。下面我们来逐步解析 DefaultListableBeanFactory 。

1.1 详解 DefaultSingletonBeanRegistry

首先,我们来看一下 DefaultSingletonBeanRegistry 中定义的方法:

public interface DefaultSingletonBeanRegistry {
    void registerSingleton(String beanName, Object singletonObject);
    Object getSingleton(String beanName);
    boolean containsSingleton(String beanName);
    String[] getSingletonNames();
    int getSingletonCount();
}

可以看到,DefaultSingletonBeanRegistry 定义了单例 Bean 的注册、缓存和查询接口,包括 registerSingleton()、getSingleton()、containsSingleton()、getSingletonNames()和 getSingletonCount() 等方法。其中,registerSingleton() 方法用于将一个单例 Bean注册到缓存中,getSingleton() 方法用于获取指定名称的单例 Bean,containsSingleton()方法用于判断指定名称的单例 Bean 是否存在,getSingletonNames() 方法用于获取所有单例 Bean 的名称,getSingletonCount() 方法用于获取单例 Bean 的数量。

接下来我们看下 DefaultSingletonBeanRegistry 的实现,我给源码中添加一些注释方便大家理解

尤其大家可以看下spring 在单例实现中的线程安全是怎么做到额

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable, DefaultSingletonBeanRegistry {
    // ...
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); // 单例对象缓存
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 单例对象工厂缓存
    private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16); // 提前暴露的单例对象缓存
    private final Set<String> registeredSingletons = new LinkedHashSet<>(256); // 已注册的单例对象集合
    private final Set<String> disposableBeans = new LinkedHashSet<>(256); // 需要销毁的单例对象集合
    // ...
    @Override
    public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
        Assert.notNull(beanName, "Bean name must not be null"); // beanName 不能为空
        synchronized (this.singletonObjects) { // 加锁,确保线程安全
            Object oldObject = this.singletonObjects.get(beanName); // 查找缓存中是否已存在同名单例对象
            if (oldObject != null) {
                throw new IllegalStateException("Could not register object [" + singletonObject +
                        "] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound"); // 如果已存在同名单例对象,则抛出异常
            }
            this.singletonObjects.put(beanName, singletonObject); // 将单例对象放入缓存中
            this.singletonFactories.remove(beanName); // 从单例对象工厂缓存中移除该对象
            this.earlySingletonObjects.remove(beanName); // 从提前暴露的单例对象缓存中移除该对象
            this.registeredSingletons.add(beanName); // 将该对象名称添加到已注册的单例对象集合中
        }
    }
    @Override
    public Object getSingleton(String beanName) {
        return getSingleton(beanName, true); // 调用带有 allowEarlyReference 参数的 getSingleton() 方法
    }
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName); // 从缓存中获取指定名称的单例对象
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { // 如果缓存中不存在该单例对象,并且该对象正在创建过程中
            synchronized (this.singletonObjects) { // 加锁,确保线程安全
                singletonObject = this.earlySingletonObjects.get(beanName); // 从提前暴露的单例对象缓存中获取该对象
                if (singletonObject == null && allowEarlyReference) { // 如果提前暴露的单例对象缓存中仍未找到该对象,并且允许提前暴露
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); // 从单例对象工厂缓存中获取该对象的 ObjectFactory
                    if (singletonFactory != null) { // 如果单例对象工厂存在
                        singletonObject = singletonFactory.getObject(); // 获取新的单例对象
                        this.earlySingletonObjects.put(beanName, singletonObject); // 将新的单例对象放入提前暴露的单例对象缓存中
                        this.singletonFactories.remove(beanName); // 从单例对象工厂缓存中移除该对象
                    }
                }
            }
        }
        return singletonObject;    }
    @Override
    public boolean containsSingleton(String beanName) {
        return this.singletonObjects.containsKey(beanName); // 判断单例对象缓存中是否存在指定名称的单例对象
    }
    @Override
    public String[] getSingletonNames() {
        synchronized (this.singletonObjects) { // 加锁,确保线程安全
            return StringUtils.toStringArray(this.registeredSingletons); // 将已注册的单例对象集合转换为数组返回
        }
    }
    @Override
    public int getSingletonCount() {
        synchronized (this.singletonObjects) { // 加锁,确保线程安全
            return this.registeredSingletons.size(); // 返回已注册的单例对象集合的大小
        }
    }
    // ...
}

除了上述方法外,DefaultListableBeanFactory 还提供了一些其他方法来管理单例 Bean,例如 destroySingletons() 方法用于销毁所有的单例 Bean,getSingletonMutex() 方法用于获取单例对象的互斥锁等。


综上所述,DefaultSingletonBeanRegistry 接口及其默认实现类 DefaultListableBeanFactory 提供了一系列方法来管理单例对象的生命周期,包括注册、缓存、查询、销毁等操作,为 Spring Framework 的IoC 容器实现了核心的单例对象管理机制,确保了单例对象的唯一性和正确性。

 

3. 观察者模式

在 Spring Boot 中,观察者模式通常用于实现事件驱动的编程模型。Spring Framework 中的 ApplicationEvent 和 ApplicationListener 接口就是观察者模式的实现。ApplicationEvent 是事件对象的抽象类,它定义了事件发生时需要携带的数据。ApplicationListener 是事件监听器的接口,它定义了监听器需要实现的方法,当事件发生时,监听器会自动执行相应的处理逻辑。


在 Spring Boot 中,我们可以通过继承 ApplicationEvent 类来自定义事件对象,通过实现 ApplicationListener 接口来定义事件监听器。Spring 容器会自动扫描所有实现了 ApplicationListener 接口的 Bean,并将其注册为事件监听器。当事件发生时,Spring 容器会自动调用对应监听器的 onApplicationEvent() 方法来处理事件。


具体实现可以参考 Spring Framework 的 ApplicationEvent 和 ApplicationListener 接口,以及 AbstractApplicationContext、SimpleApplicationEventMulticaster 等类。

4. 适配器模式

在 Spring Boot 中,适配器模式通常用于将不兼容的接口转换成可兼容的接口。Spring Framework 中的适配器模式主要体现在以下两个方面:


控制器方法适配器:Spring MVC 中的控制器方法可以返回多种类型的结果,例如 ModelAndView、String、void 等,但是 Spring Boot 的 RESTful API 通常需要返回 JSON 或 XML格式的数据。为了将控制器方法的返回值转换成符合 RESTful API 要求的格式,Spring Boot 提供了多种适配器类,例如 MappingJackson2HttpMessageConverter、Jaxb2RootElementHttpMessageConverter 等。


具体实现可以参考 Spring Framework 的 HttpMessageConverter 接口及其实现类。


数据库驱动适配器:在 Spring Boot 中,JDBC 模板可以适配各种不同的数据库驱动,只需配置相应的数据源和驱动类即可。Spring Boot 中已经预置了许多常用的数据库驱动适配器,包括 H2、MySQL、PostgreSQL、Oracle 等。

具体实现可以参考 Spring Framework 的 JdbcTemplate 和 DataSource 接口及其实现类,以及 DriverManagerDataSource、HikariDataSource 等数据源实现类。

5. 模板方法模式

在 Spring Boot 中,模板方法模式通常用于实现通用的业务逻辑。Spring Framework 中的 JdbcTemplate 和 HibernateTemplate 就是模板方法模式的实现。这些模板类定义了通用的数据访问操作,如查询、插入、更新、删除等,而具体的数据访问细节则由子类(如 JdbcDaoSupport、HibernateDaoSupport 等)来实现。


我们可以使用 JdbcTemplate 来执行 SQL 操作,它封装了 JDBC

的基本操作,如打开和关闭连接、创建和执行语句等。我们可以通过定义 RowMapper 接口来映射查询结果集到对象上,JdbcTemplate

会自动将查询结果集转换成对象列表。具体实现可以参考 Spring Framework 的 JdbcTemplate 和 RowMapper

接口及其实现类,以及 NamedParameterJdbcTemplate、SimpleJdbcInsert 等模板类。


30564414fda34523819471a657f0031f.png

好了,我是冰点,今天的分享就到这儿,下次见,如果对你有帮助点赞收藏,如果有疑问可以在评论区留言。

目录
相关文章
|
7天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
22 2
|
23天前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
148 1
|
1月前
|
设计模式 PHP
PHP中的设计模式:单一职责原则在软件开发中的应用
【10月更文挑战第8天】 在软件开发中,设计模式是解决常见问题的经验总结,而单一职责原则作为面向对象设计的基本原则之一,强调一个类应该只有一个引起变化的原因。本文将探讨单一职责原则在PHP中的应用,通过实际代码示例展示如何运用该原则来提高代码的可维护性和可扩展性。
33 1
|
21天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,创建并配置 Spring Boot 项目,实现后端 API;然后,使用 Ant Design Pro Vue 创建前端项目,配置动态路由和菜单。通过具体案例,展示了如何快速搭建高效、易维护的项目框架。
96 62
|
13天前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
39 9
|
19天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,帮助开发者提高开发效率和应用的可维护性。
37 2
|
22天前
|
设计模式 存储 数据库连接
PHP中的设计模式:单例模式的深入理解与应用
【10月更文挑战第22天】 在软件开发中,设计模式是解决特定问题的通用解决方案。本文将通过通俗易懂的语言和实例,深入探讨PHP中单例模式的概念、实现方法及其在实际开发中的应用,帮助读者更好地理解和运用这一重要的设计模式。
15 1
|
1月前
|
设计模式 PHP 开发者
PHP中的设计模式:桥接模式的解析与应用
在软件开发的浩瀚海洋中,设计模式如同灯塔一般,为开发者们指引方向。本文将深入探讨PHP中的一种重要设计模式——桥接模式。桥接模式巧妙地将抽象与实现分离,通过封装一个抽象的接口,使得实现和抽象可以独立变化。本文将阐述桥接模式的定义、结构、优缺点及其应用场景,并通过具体的PHP示例代码展示如何在实际项目中灵活运用这一设计模式。让我们一起走进桥接模式的世界,感受它的魅力所在。
|
1月前
|
设计模式 测试技术 持续交付
架构视角下的NHibernate:设计模式与企业级应用考量
【10月更文挑战第13天】随着软件开发向更复杂、更大规模的应用转变,数据访问层的设计变得尤为重要。NHibernate作为一个成熟的对象关系映射(ORM)框架,为企业级.NET应用程序提供了强大的支持。本文旨在为有一定经验的开发者提供一个全面的指南,介绍如何在架构层面有效地使用NHibernate,并结合领域驱动设计(DDD)原则来构建既强大又易于维护的数据层。
38 2