SpringBoot——自动装配原理

@EnableAutoConfiguration

SpringBoot启动的时候加载主配置类,开启了自动配置功能 @EnableAutoConfiguration

在spring中有关于 @Enablexxx 的注解是开启某一项功能的注解,比如 @EnableScheduling 表示开启spring的定时任务。其原理是借助 @Import 的帮助,将所有符合自动配置条件的bean定义加载到Ioc容器。

1
2
3
4
5
6
7
8
9
10
11
12
13
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
//按类型排序不需要自动装配的类
Class<?>[] exclude() default {};
//按名称排除不需要自动装配的类
String[] excludeName() default {};
}

从源码中可以知道,最关键的要属 @Import(EnableAutoConfigurationImportSelector.class),借助EnableAutoConfigurationImportSelector@EnableAutoConfiguration 可以帮助SpringBoot应用将所有符合条件的 @Configuration 配置都加载到当前SpringBoot创建并使用的IoC容器。

同时借助于 Spring 框架原有的一个工具类:SpringFactoriesLoader,@EnableAutoConfiguration 就可以实现智能的自动配置。

  1. @EnableAutoConfiguration 作用就是从classpath中搜寻所有的 META-INF/spring.factories 配置文件

  2. 将其中 org.springframework.boot.autoconfigure.EnableutoConfiguration 对应的配置项通过反射(Java Refletion)实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类,然后汇总为一个并加载到IoC容器。

  3. 这些功能配置类要生效的话,会去classpath中找是否有该类的依赖类,所以功能类能生效需要的条件:

    • spring.factories里面有这个类的配置类(一个配置类可以创建多个围绕该功能的依赖类)
    • pom.xml里面需要有对应的jar包

以Redis自动装配为例

  1. 从spring-boot-autoconfigure.jar/META-INF/spring.factories中获取redis的相关配置类全限定名(有120多个的配置类)RedisAutoConfiguration

  2. RedisAutoConfiguration配置类生效的一个条件是在classpath路径下有RedisOperations类存在,因此springboot的自动装配机制会会去classpath下去查找对应的class文件。 其中 @ConditionalOnClass 注解是关键。

1
2
3
4
5
6
@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
...}
  1. 如果pom.xml有对应的jar包,就能匹配到对应依赖class
1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  1. 匹配成功,这个功能配置类才会生效,同时会注入默认的属性配置类 @EnableConfigurationProperties(RedisProperties.class)
1
2
3
4
5
6
7
8
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
private int database = 0;
private String url;
private String host = "localhost";
private String password;
private int port = 6379;
...
  1. Redis功能配置里面会根据条件生成最终的JedisConnectionFactory、RedisTemplate,并提供了默认的配置形式@ConditionalOnMissingBean(name = “redisTemplate”)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {

@Bean
//用户没定义就使用默认的
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(
RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}

@Bean
@ConditionalOnMissingBean(StringRedisTemplate.class)
public StringRedisTemplate stringRedisTemplate(
RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}

}

总结

  1. 容器在启动的时候Application.run,会调用EnableAutoConfigurationImportSelector.class的selectImports方法(其实是其父类的方法)

  2. selectImports方法最终会调用SpringFactoriesLoader.loadFactoryNames方法来获取一个全面的常用BeanConfiguration列表

  3. loadFactoryNames方法会读取 FACTORIES_RESOURCE_LOCATION(也就是spring-boot-autoconfigure.jar 下面的spring.factories),获取到所有的Spring相关的Bean的全限定名ClassName,大概120多个

  4. selectImports 方法继续调用 filter(configurations, autoConfigurationMetadata);这个时候会根据这些BeanConfiguration里面的条件,来一一筛选,最关键的是 @ConditionalOnClass,这个条件注解会去classpath下查找,jar包里面是否有这个条件依赖类,所以必须有了相应的jar包,才有这些依赖类,才会生成IOC环境需要的一些默认配置Bean

  5. 最后把符合条件的BeanConfiguration注入默认的EnableConfigurationPropertie类里面的属性值,并且注入到IOC环境当中

文章目录
  1. 1. @EnableAutoConfiguration
  2. 2. 以Redis自动装配为例
  3. 3. 总结
|