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

简介: 背景:大家好,我是冰点。最近有网友反馈,他在面试过程中被面试官问到,设计模式,他按自己背设计模式的八股文回答了,之后面试官又追问了一句,那你知道 你们项目所用的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

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

目录
相关文章
|
10月前
|
消息中间件 缓存 Java
Spring框架优化:提高Java应用的性能与适应性
以上方法均旨在综合考虑Java Spring 应该程序设计原则, 数据库交互, 编码实践和系统架构布局等多角度因素, 旨在达到高效稳定运转目标同时也易于未来扩展.
816 8
|
11月前
|
设计模式 人工智能 算法
基于多设计模式的状态扭转设计:策略模式与责任链模式的实战应用
接下来,我会结合实战案例,聊聊如何用「策略模式 + 责任链模式」构建灵活可扩展的状态引擎,让抽奖系统的状态管理从「混乱战场」变成「有序流水线」。
设计模式 存储 人工智能
754 0
|
11月前
|
SQL Java 数据库连接
Spring Data JPA 技术深度解析与应用指南
本文档全面介绍 Spring Data JPA 的核心概念、技术原理和实际应用。作为 Spring 生态系统中数据访问层的关键组件,Spring Data JPA 极大简化了 Java 持久层开发。本文将深入探讨其架构设计、核心接口、查询派生机制、事务管理以及与 Spring 框架的集成方式,并通过实际示例展示如何高效地使用这一技术。本文档约1500字,适合有一定 Spring 和 JPA 基础的开发者阅读。
947 0
|
12月前
|
Java 应用服务中间件 开发者
Spring Boot 技术详解与应用实践
本文档旨在全面介绍 Spring Boot 这一广泛应用于现代企业级应用开发的框架。内容将涵盖 Spring Boot 的核心概念、核心特性、项目自动生成与结构解析、基础功能实现(如 RESTful API、数据访问)、配置管理以及最终的构建与部署。通过本文档,读者将能够理解 Spring Boot 如何简化 Spring 应用的初始搭建和开发过程,并掌握其基本使用方法。
794 2
|
12月前
|
设计模式 XML 安全
Java枚举(Enum)与设计模式应用
Java枚举不仅是类型安全的常量,还具备面向对象能力,可添加属性与方法,实现接口。通过枚举能优雅实现单例、策略、状态等设计模式,具备线程安全、序列化安全等特性,是编写高效、安全代码的利器。
|
12月前
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。
1460 0
|
12月前
|
人工智能 监控 安全
如何快速上手【Spring AOP】?核心应用实战(上篇)
哈喽大家好吖~欢迎来到Spring AOP系列教程的上篇 - 应用篇。在本篇,我们将专注于Spring AOP的实际应用,通过具体的代码示例和场景分析,帮助大家掌握AOP的使用方法和技巧。而在后续的下篇中,我们将深入探讨Spring AOP的实现原理和底层机制。 AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的核心特性之一,它能够帮助我们解决横切关注点(如日志记录、性能统计、安全控制、事务管理等)的问题,提高代码的模块化程度和复用性。
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
1519 3
|
安全 算法 Java
在Spring Boot中应用Jasypt以加密配置信息。
通过以上步骤,可以在Spring Boot应用中有效地利用Jasypt对配置信息进行加密,这样即使配置文件被泄露,其中的敏感信息也不会直接暴露给攻击者。这是一种在不牺牲操作复杂度的情况下提升应用安全性的简便方法。
1611 10