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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 背景:大家好,我是冰点。最近有网友反馈,他在面试过程中被面试官问到,设计模式,他按自己背设计模式的八股文回答了,之后面试官又追问了一句,那你知道 你们项目所用的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

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

目录
相关文章
|
3天前
|
设计模式 安全 数据库连接
后端开发中的设计模式应用
在软件开发的浩瀚海洋中,设计模式如同灯塔,为后端开发者指引方向。它们不仅仅是代码的模板,更是解决复杂问题的智慧结晶。本文将深入探讨几种常见的设计模式,包括单例模式、工厂模式和观察者模式,并揭示它们在实际应用中如何提升代码的可维护性、扩展性和重用性。通过实例分析,我们将一窥这些模式如何在后端开发中大放异彩,助力构建高效、灵活的软件系统。
|
16天前
|
安全 Java 网络安全
当网络安全成为数字生活的守护者:Spring Security,为您的应用筑起坚不可摧的防线
【9月更文挑战第2天】在数字化时代,网络安全至关重要。本文通过在线银行应用案例,详细介绍了Spring Security这一Java核心安全框架的核心功能及其配置方法。从身份验证、授权控制到防御常见攻击,Spring Security提供了全面的解决方案,确保应用安全。通过示例代码展示了如何配置`WebSecurityConfigurerAdapter`及`HttpSecurity`,帮助开发者有效保护应用免受安全威胁。
39 4
|
4天前
|
缓存 Java 开发工具
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
三级缓存是Spring框架里,一个经典的技术点,它很好地解决了循环依赖的问题,也是很多面试中会被问到的问题,本文从源码入手,详细剖析Spring三级缓存的来龙去脉。
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
|
4天前
|
XML 缓存 Java
手写Spring源码(简化版)
Spring包下的类、手写@ComponentScan注解、@Component注解、@Autowired注解、@Scope注解、手写BeanDefinition、BeanNameAware、InitializingBean、BeanPostProcessor 、手写AnnotationConfigApplicationContext
手写Spring源码(简化版)
|
4天前
|
缓存 安全 Java
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
从底层源码入手,通过代码示例,追踪AnnotationConfigApplicationContext加载配置类、启动Spring容器的整个流程,并对IOC、BeanDefinition、PostProcesser等相关概念进行解释
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
|
4天前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
|
5天前
|
设计模式 数据库连接 PHP
PHP中的设计模式应用与最佳实践
在本文中,我们将探讨PHP设计模式的应用和最佳实践。通过深入分析,揭示如何在实际项目中有效利用设计模式来优化代码结构、提升系统灵活性和维护性,并分享一些常见设计模式的实际应用案例。无论你是PHP初学者还是经验丰富的开发者,这篇文章都会对你有所帮助。
|
16天前
|
IDE Java 开发工具
还在为繁琐的配置头疼吗?一文教你如何用 Spring Boot 快速启动,让开发效率飙升,从此告别加班——打造你的首个轻量级应用!
【9月更文挑战第2天】Spring Boot 是一款基于 Spring 框架的简化开发工具包,采用“约定优于配置”的原则,帮助开发者快速创建独立的生产级应用程序。本文将指导您完成首个 Spring Boot 项目的搭建过程,包括环境配置、项目初始化、添加依赖、编写控制器及运行应用。首先需确保 JDK 版本不低于 8,并安装支持 Spring Boot 的现代 IDE,如 IntelliJ IDEA 或 Eclipse。
51 5
|
1天前
|
设计模式 算法 PHP
PHP中的设计模式:策略模式的应用与实践
在软件开发中,设计模式是解决问题的最佳实践。本文将探讨PHP中的策略模式,通过实际应用案例,展示如何有效地使用策略模式来提高代码的灵活性和可维护性。我们将从基本概念入手,逐步深入到实际编码,最终实现一个具有策略模式的应用。
|
18天前
|
前端开发 C# 设计模式
“深度剖析WPF开发中的设计模式应用:以MVVM为核心,手把手教你重构代码结构,实现软件工程的最佳实践与高效协作”
【8月更文挑战第31天】设计模式是在软件工程中解决常见问题的成熟方案。在WPF开发中,合理应用如MVC、MVVM及工厂模式等能显著提升代码质量和可维护性。本文通过具体案例,详细解析了这些模式的实际应用,特别是MVVM模式如何通过分离UI逻辑与业务逻辑,实现视图与模型的松耦合,从而优化代码结构并提高开发效率。通过示例代码展示了从模型定义、视图模型管理到视图展示的全过程,帮助读者更好地理解并应用这些模式。
32 0