Spring Boot的自动配置是指Spring Boot根据应用程序的依赖和配置信息,自动为应用程序进行配置,减少了开发人员手动配置的工作量。
Spring Boot的自动配置基于条件注解和Spring Boot Starter的机制。条件注解是通过判断一定的条件是否满足来决定是否应用某个配置。Spring Boot Starter是一种特殊的依赖,它包含了一组相关的依赖和配置,可以通过引入该Starter来自动配置相关的功能。
Spring Boot的自动配置可以通过以下几种方式实现:
1. 使用@EnableAutoConfiguration注解
2. 使用@ConfigurationProperties注解
1. 使用@EnableAutoConfiguration注解
在Spring Boot的主配置类上添加@EnableAutoConfiguration注解,Spring Boot会根据类路径上的依赖自动进行配置。@Enable底层依赖于@Import注解导入一些类,使用@Import导入的类会被Spring加载到IOC容器中。而@Import提供4中用法:
- ① 导入Bean
- ② 导入配置类
- ③ 导入 ImportSelector 实现类。一般用于加载配置文件中的类
- ④ 导入 ImportBeanDefinitionRegistrar 实现类。
@SpringBootApplication注解内部
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
// ......
}
@ComponentScan
这个注解在Spring中很重要 ,它对应XML配置中的元素。
作用:自动扫描并加载符合条件的组件或者bean , 将这个bean定义加载到IOC容器中
@SpringBootConfiguration
作用:SpringBoot的配置类 ,标注在某个类上 , 表示这是一个SpringBoot的配置类;
//@SpringBootConfiguration注解内部
//这里的 @Configuration,说明这是一个配置类 ,配置类就是对应Spring的xml 配置文件;
@Configuration
public @interface SpringBootConfiguration {}
//里面的 @Component 这就说明,启动类本身也是Spring中的一个组件而已,负责启动应用
@Component
public @interface Configuration {}
@AutoConfigurationPackage :自动配置包
//AutoConfigurationPackage的子注解
//Registrar.class 作用:将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}
@EnableAutoConfiguration开启自动配置功能
以前我们需要自己配置的东西,而现在SpringBoot可以自动帮我们配置 ;需要告诉SpringBoot开启自动配置功能,这样自动配置才能生效;
@Import({AutoConfigurationImportSelector.class}) :给容器导入组件
@AutoConfigurationImportSelector :自动配置导入选择器,给容器中导入一些组件
AutoConfigurationImportSelector.class
↓
selectImports方法
↓
this.getAutoConfigurationEntry(annotationMetadata)方法
↓
this.getCandidateConfigurations(annotationMetadata, attributes)方法
↓
方法体:
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
↓
在所有包名叫做autoConfiguration的包下面都有META-INF/spring.factories文件
总结原理:
- @EnableAutoConfiguration 注解内部使用
-@Import(AutoConfigurationImportSelector.**class**)来加载配置类。
- 配置文件位置:META-INF/spring.factories,该配置文件中定义了大量的配置类,当 SpringBoot 应用启动时,会自动加载这些配置类,初始化Bean
- 并不是所有的Bean都会被初始化,在配置类中使用Condition来加载满足条件的Bean
2. 使用@ConfigurationProperties注解
通过在配置类中使用@ConfigurationProperties注解,可以将配置文件中的属性值自动绑定到配置类的属性上。以导入Redis为例
RedisProperties
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
private String host="localhost";
private int port=6379;
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
}
主配置类中自动加载RedisProperties
@Configuration
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoconfiguration {
//注入jedis
//@ConditionalOnBean
@Bean
public Jedis jedis(RedisProperties redisProperties){
return new Jedis(redisProperties.getHost(),redisProperties.getPort());
}
}
3. 使用@Conditional注解
通过在配置类或Bean上使用@Conditional注解,可以根据条件来决定是否应用某个配置或创建某个Bean。
- ConditionalOnProperty:判断配置文件中是否有对应属性和值才初始化Bean
- ConditionalOnClass:判断环境中是否有对应字节码文件才初始化Bean
- ConditionalOnMissingBean:判断环境中没有对应Bean才初始化Bean
- ConditionalOnBean:判断环境中有对应Bean才初始化Bean
以导入Jedis坐标后创建Bean为例,基本思路是:判断redis.clients.jedis.Jedis.class文件是否存在
- 首先创建一个User类,可以是空类;
- 其次创建ClassCondition继承自Condition
-
public class ClassCondition implements Condition { /** * * @param context 上下文对象。用于获取环境,IOC容器,ClassLoader对象 * @param metadata 注解元对象。 可以用于获取注解定义的属性值 * @return */ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { //1.需求: 导入Jedis坐标后创建Bean //思路:判断redis.clients.jedis.Jedis.class文件是否存在 boolean flag = true; try{ Class<?> cls = Class.forName("redis.clients.jedis.Jedis"); } catch (ClassNotFoundException e) { flag = false; } return flag; } }
- 将ClassCondition加入主配置类
-
@Configuration public class UserConfig { @Bean @Conditional(value = ClassCondition.class) public User user(){ return new User(); } }
- 测试
-
@SpringBootApplication public class DemoApplication { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args); //获取Bean,redisTemplate //情况1 没有添加坐标前,发现为空 //情况2 有添加坐标前,发现有对象 // Object redisTemplate = context.getBean("redisTemplate"); // System.out.println(redisTemplate); /********************案例1********************/ Object user = context.getBean("user"); System.out.println(user); } }
4. 使用Spring Boot Starter自定义配置
通过引入Spring Boot Starter依赖,可以自动配置相关的功能。例如,引入spring-boot-starter-web依赖可以自动配置Web应用程序所需的相关功能。可以在模块中引入自定义的配置。
<!--引入自定义的redis-spring-boot-autoconfigure-->
<dependency>
<groupId>com.apesource</groupId>
<artifactId>redis-spring-boot-autoconfigure</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
实现步骤
- 创建redis-spring-boot-autoconfigure模块
- 创建redis-spring-boot-starter模块,依赖redis-spring-boot-autoconfigure的模块
- 在redis-spring-boot-autoconfigure模块中初始化Jedis的Bean,并定义META-INF/spring.factories文件
- 在测试模块中引入自定义的redis-starter依赖,测试获取Jedis的Bean,操作redis。