文章目录
-
- 一、自动装配原理
-
- [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
注解。
自动装配的实现主要依靠三个核心的关键技术:
-
引入
Starter
启动依赖组件,这个组件里面必须要包含一个@Configuration
配置类,而在这个配置类里面,需要通过@Bean
这个注解声明需要装配到IOC容器里面的Bean对象。 -
这个配置类是放在第三方的
jar
包里,然后通过SpringBoot中,约定优于配置 的理念,通过Spring里面的SpringFactoriesLoader
类,把这个配置类的全路径 放在classpath:/META-INF/spring.factories
文件里,这样的话,SpringBoot就可以知道第三方jar
包里这个配置类的位置。 -
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通过自动装配和默认配置,使得开发者可以更专注于业务逻辑的实现,而无需过多关注底层框架的配置和管理,从而实现了零配置和快速开发的特性。
- 约定优于配置: SpringBoot通过约定优于配置的原则,提供了大量的默认配置 和自动装配策略。这意味着在绝大多数情况下,开发者无需手动进行繁琐的配置,而是可以直接使用默认的配置和自动装配功能,从而实现了零配置的效果。
- 自动发现与注册: SpringBoot利用组件扫描 和条件化配置等技术,可以自动发现项目中的各种Bean,并将其注册到Spring的应用上下文中。这意味着开发者无需手动向Spring注册每一个Bean,而是可以依靠自动装配的能力,让Spring自动管理和连接各个组件。
- 快速集成: SpringBoot提供了大量的自动配置类 ,可以根据项目的依赖和环境自动集成各种中间件和框架(如数据库、消息队列、Web服务器等),并提供了默认的配置 和实例化过程。这使得开发者可以轻松地集成第三方组件,而无需深入了解它们的具体配置和使用方式,从而实现了快速开发的目标。
2.2 组件扫描、条件装配实现自动配置
组件扫描和条件装配使得SpringBoot能够根据项目的实际情况和环境条件来自动化地完成配置和组件的注册,从而实现了自动配置的功能。
- 组件扫描: Spring框架可以通过组件扫描的方式来发现和注册标记了特定注解的组件,比如
@Component
、@Service
、@Repository
、@Controller
等。在SpringBoot中,通过在启动类上加上@SpringBootApplication
注解,就会启用组件扫描,Spring Boot会自动扫描启动类所在包及其子包下的所有组件,并将其纳入Spring容器的管理范围。 - 条件装配: Spring Boot利用条件装配的机制,根据特定的条件来决定是否应该创建某个Bean或者加载某个配置类。这些条件通常是通过
@ConditionalOnXXX
系列注解来指定的,比如@ConditionalOnClass
、@ConditionalOnMissingBean
、@ConditionalOnProperty
等。通过这些条件注解,可以在特定条件满足时自动激活某个Bean的创建或者某个配置类的加载。
SpringBoot实现自动配置的过程:
- 自动发现组件: 通过组件扫描,SpringBoot可以自动发现项目中的各种组件,如控制器、服务、仓储等。
- 根据条件加载配置: 通过条件装配,SpringBoot可以根据特定的条件来加载配置类或者创建Bean,比如在特定的类存在时加载对应的配置,或者在特定的Bean不存在时创建默认的实例。
- 集成第三方组件: 通过条件装配,Spring Boot可以根据项目的依赖情况自动集成第三方组件,比如在项目中引入了某个数据库驱动时,自动配置数据源、事务管理器等相关组件。
三、自定义自动装配
3.1 @EnableAutoConfiguration注解来扩展和修改Spring Boot的自动配置
三种常用方法:
-
使用
exclude
属性排除特定的自动配置类:通过在
@EnableAutoConfiguration
注解上使用exclude
属性,可以排除特定的自动配置类,从而禁用某些默认的自动配置。(适用于想要排除某些默认配置的情况)java@SpringBootApplication @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class}) public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } }
-
自定义配置类覆盖默认配置:
编写自定义的配置类,并在其中定义自己的 Bean,以覆盖默认的自动配置。(适用于想要修改默认配置或添加新的配置的情况)
java@Configuration public class MyConfiguration { @Bean public MyBean myBean() { return new MyBean(); } }
-
使用
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
注解来实现这一需求。
- 创建一个配置属性类
DatabaseProperties
。
java
/**
* 使用 @ConfigurationProperties 注解标记该类,以便将外部配置文件中的属性值绑定到该类的属性上
*/
@Component
@ConfigurationProperties("myapp.database")
public class DatabaseProperties {
private String url;
private String username;
private String password;
// getters && setters
}
- 在自动配置类中使用
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;
}
}
- 外部配置文件中设置数据库连接的属性值。
properties
myapp.database.url=jdbc:mysql://localhost:3306/mydatabase
myapp.database.username=myusername
myapp.database.password=mypassword
后悔过去,不如奋斗将来