解密Spring Boot:揭秘自动装配背后的原理与机制

文章目录

    • 一、自动装配原理
      • [1.1 实现原理和机制](#1.1 实现原理和机制)
      • [1.2 原理案例](#1.2 原理案例)
        • [1.2.1 pom.xml](#1.2.1 pom.xml)
        • [1.2.2 SpringFactoriesLoader.class](#1.2.2 SpringFactoriesLoader.class)
        • [1.2.3 spring.factories](#1.2.3 spring.factories)
        • [1.2.4 ImportSelector](#1.2.4 ImportSelector)
    • 二、自动装配特性
      • [2.1 自动装配实现零配置和快速开发的特性](#2.1 自动装配实现零配置和快速开发的特性)
      • [2.2 组件扫描、条件装配实现自动配置](#2.2 组件扫描、条件装配实现自动配置)
    • 三、自定义自动装配
      • [3.1 @EnableAutoConfiguration注解来扩展和修改Spring Boot的自动配置](#3.1 @EnableAutoConfiguration注解来扩展和修改Spring Boot的自动配置)
      • [3.2 @ConfigurationProperties 注解来扩展和修改Spring Boot的自动配置](#3.2 @ConfigurationProperties 注解来扩展和修改Spring Boot的自动配置)

一、自动装配原理

1.1 实现原理和机制

自动装配实际上就是把第三方组件的Bean装载到IOC容器里,不需要开发人员再去写Bean相关的一个配置。

在SpringBoot应用里,只需要在启动类上加上@SpringBootApplication注解,就可以去实现自动装配。 @SpringBootApplication注解是一个复合注解,真正去实现自动装配的注解是@EnableAutoConfiguration注解。

自动装配的实现主要依靠三个核心的关键技术

  1. 引入Starter启动依赖组件,这个组件里面必须要包含一个@Configuration配置类,而在这个配置类里面,需要通过@Bean这个注解声明需要装配到IOC容器里面的Bean对象。

  2. 这个配置类是放在第三方的jar包里,然后通过SpringBoot中,约定优于配置 的理念,通过Spring里面的SpringFactoriesLoader类,把这个配置类的全路径 放在 classpath:/META-INF/spring.factories文件里,这样的话,SpringBoot就可以知道第三方jar包里这个配置类的位置。

  3. SpringBoot拿到所有第三方jar包里面声明的配置类以后,再通过Spring提供的ImportSelector这样一个接口,来实现对这些配置类的动态加载,从而去完成自动装配这样一个动作。

自动装配的思想,在SpringFramework3.x版本里,@Enable注解就已经有了实现的一个雏形,@Enable注解是一个模块驱动 的意思,也就是说只需要增加@Enable注解,就能自动打开某个功能,而不需要针对这个功能去做Bean的配置。@Enable注解的底层自动去完成这样一个模块,相关Bean注入的。

1.2 原理案例

本文以mybatis-plus-boot-starter第三方组件来展开自动装配的流程。

1.2.1 pom.xml

下图是引入Starter启动依赖组件,对于第三方依赖里是否需要包含一个 @Configuration 配置类,并且在该配置类中通过 @Bean 注解声明需要装配到 IOC 容器中的 Bean 对象 。感兴趣的读者可自行查看官方文档或者 GitHub 仓库中的 README 文件或者查看 mybatis-plus-boot-starter 组件的源码等方式验证。

1.2.2 SpringFactoriesLoader.class

用于加载 Spring 配置工厂的工具类 SpringFactoriesLoader,它提供了一种机制来加载并实例化指定类型的工厂类。

1.2.3 spring.factories

用于在 Spring Boot 应用程序中自动配置和装配相关的组件和功能。

1.2.4 ImportSelector

用于在 Spring 中选择需要导入的类。具体的实现类感兴趣的读者可自行解读。

二、自动装配特性

2.1 自动装配实现零配置和快速开发的特性

SpringBoot通过自动装配和默认配置,使得开发者可以更专注于业务逻辑的实现,而无需过多关注底层框架的配置和管理,从而实现了零配置和快速开发的特性。

  1. 约定优于配置: SpringBoot通过约定优于配置的原则,提供了大量的默认配置自动装配策略。这意味着在绝大多数情况下,开发者无需手动进行繁琐的配置,而是可以直接使用默认的配置和自动装配功能,从而实现了零配置的效果。
  2. 自动发现与注册: SpringBoot利用组件扫描条件化配置等技术,可以自动发现项目中的各种Bean,并将其注册到Spring的应用上下文中。这意味着开发者无需手动向Spring注册每一个Bean,而是可以依靠自动装配的能力,让Spring自动管理和连接各个组件。
  3. 快速集成: SpringBoot提供了大量的自动配置类 ,可以根据项目的依赖和环境自动集成各种中间件和框架(如数据库、消息队列、Web服务器等),并提供了默认的配置实例化过程。这使得开发者可以轻松地集成第三方组件,而无需深入了解它们的具体配置和使用方式,从而实现了快速开发的目标。

2.2 组件扫描、条件装配实现自动配置

组件扫描和条件装配使得SpringBoot能够根据项目的实际情况和环境条件来自动化地完成配置和组件的注册,从而实现了自动配置的功能。

  1. 组件扫描: Spring框架可以通过组件扫描的方式来发现和注册标记了特定注解的组件,比如@Component@Service@Repository@Controller等。在SpringBoot中,通过在启动类上加上@SpringBootApplication注解,就会启用组件扫描,Spring Boot会自动扫描启动类所在包及其子包下的所有组件,并将其纳入Spring容器的管理范围。
  2. 条件装配: Spring Boot利用条件装配的机制,根据特定的条件来决定是否应该创建某个Bean或者加载某个配置类。这些条件通常是通过@ConditionalOnXXX系列注解来指定的,比如@ConditionalOnClass@ConditionalOnMissingBean@ConditionalOnProperty等。通过这些条件注解,可以在特定条件满足时自动激活某个Bean的创建或者某个配置类的加载。

SpringBoot实现自动配置的过程

  1. 自动发现组件: 通过组件扫描,SpringBoot可以自动发现项目中的各种组件,如控制器、服务、仓储等。
  2. 根据条件加载配置: 通过条件装配,SpringBoot可以根据特定的条件来加载配置类或者创建Bean,比如在特定的类存在时加载对应的配置,或者在特定的Bean不存在时创建默认的实例。
  3. 集成第三方组件: 通过条件装配,Spring Boot可以根据项目的依赖情况自动集成第三方组件,比如在项目中引入了某个数据库驱动时,自动配置数据源、事务管理器等相关组件。

三、自定义自动装配

3.1 @EnableAutoConfiguration注解来扩展和修改Spring Boot的自动配置

三种常用方法:

  1. 使用 exclude 属性排除特定的自动配置类

    通过在 @EnableAutoConfiguration 注解上使用 exclude 属性,可以排除特定的自动配置类,从而禁用某些默认的自动配置。(适用于想要排除某些默认配置的情况)

    java 复制代码
    @SpringBootApplication
    @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
    public class MyApplication {
        public static void main(String[] args) {
            SpringApplication.run(MyApplication.class, args);
        }
    }
  2. 自定义配置类覆盖默认配置

    编写自定义的配置类,并在其中定义自己的 Bean,以覆盖默认的自动配置。(适用于想要修改默认配置或添加新的配置的情况)

    java 复制代码
    @Configuration
    public class MyConfiguration {
        @Bean
        public MyBean myBean() {
            return new MyBean();
        }
    }
  3. 使用 excludeName 属性排除特定的自动配置类

    类似于 exclude 属性,可以使用 excludeName 属性来排除特定的自动配置类。不同之处在于,excludeName 属性接受类名的字符串数组,而 exclude 属性接受的是类对象数组。(适用于排除那些无法直接引用的类)

    java 复制代码
    @SpringBootApplication
    @EnableAutoConfiguration(excludeName = {"org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration"})
    public class MyApplication {
        public static void main(String[] args) {
            SpringApplication.run(MyApplication.class, args);
        }
    }

案例分析:Spring Boot 应用需要使用 Redis 作为缓存存储,而默认情况下 Spring Boot 并不会自动配置 Redis 缓存。为了实现这一需求,你需要扩展自动配置并添加 Redis 缓存的支持。

案例Demo:

java 复制代码
/**
 * 添加 @EnableAutoConfiguration 注解,并指定需要扩展的自动配置类
 */
@SpringBootApplication
@EnableAutoConfiguration(exclude = RedisAutoConfiguration.class) // 排除默认的 Redis 自动配置
@EnableCaching // 启用缓存功能
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

/**
 * 创建一个自定义的配置类,使用 @Configuration 注解,并在其中配置 Redis 缓存相关的 Bean
 */
@Configuration
public class RedisConfig {
    
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
   // 设置 Redis 连接工厂和键序列化器
   template.setConnectionFactory(redisConnectionFactory);
   template.setKeySerializer(new StringRedisSerializer());
    // 还可以配置其他序列化器、设置默认过期时间等
    return template;
    }
}

3.2 @ConfigurationProperties 注解来扩展和修改Spring Boot的自动配置

@ConfigurationProperties 注解允许将外部配置文件中的属性值绑定到一个特定的类上,从而定义自己的配置属性,并将它们与自动配置类关联起来,从而实现对自动配置的扩展和修改。

案例分析: Spring Boot 应用程序需要连接到一个名为 "MyDatabase" 的数据库,并且能够在配置文件中指定数据库的连接信息。

ps:可以使用 @ConfigurationProperties 注解来实现这一需求。

  1. 创建一个配置属性类 DatabaseProperties
java 复制代码
/**
 * 使用 @ConfigurationProperties 注解标记该类,以便将外部配置文件中的属性值绑定到该类的属性上
 */
@Component
@ConfigurationProperties("myapp.database")
public class DatabaseProperties {
    private String url;
    private String username;
    private String password;

    // getters && setters
}
  1. 在自动配置类中使用 DatabaseProperties 类。
java 复制代码
/**
 * 将其注入到自动配置中,并使用其中定义的属性值进行数据库连接的配置
 */
@Configuration
@EnableConfigurationProperties(DatabaseProperties.class)
public class DatabaseAutoConfiguration {
    private final DatabaseProperties databaseProperties;

    public DatabaseAutoConfiguration(DatabaseProperties databaseProperties) {
        this.databaseProperties = databaseProperties;
    }

    @Bean
    public DataSource dataSource() {
        // 使用 databaseProperties 中的属性值进行数据源配置
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setUrl(databaseProperties.getUrl());
        dataSource.setUsername(databaseProperties.getUsername());
        dataSource.setPassword(databaseProperties.getPassword());
        return dataSource;
    }
}
  1. 外部配置文件中设置数据库连接的属性值。
properties 复制代码
myapp.database.url=jdbc:mysql://localhost:3306/mydatabase
myapp.database.username=myusername
myapp.database.password=mypassword

后悔过去,不如奋斗将来

相关推荐
Chef_Chen几秒前
从0开始学习机器学习--Day14--如何优化神经网络的代价函数
神经网络·学习·机器学习
WaaTong12 分钟前
《重学Java设计模式》之 原型模式
java·设计模式·原型模式
m0_7430484412 分钟前
初识Java EE和Spring Boot
java·java-ee
2403_8757368713 分钟前
道品科技智慧农业中的自动气象检测站
网络·人工智能·智慧城市
AskHarries14 分钟前
Java字节码增强库ByteBuddy
java·后端
荒Huang16 分钟前
Linux挖矿病毒(kswapd0进程使cpu爆满)
linux·运维·服务器
海阔天空_201326 分钟前
Python pyautogui库:自动化操作的强大工具
运维·开发语言·python·青少年编程·自动化
佳佳_28 分钟前
Spring Boot 应用启动时打印配置类信息
spring boot·后端
小灰灰__34 分钟前
IDEA加载通义灵码插件及使用指南
java·ide·intellij-idea
零意@34 分钟前
ubuntu切换不同版本的python
windows·python·ubuntu