本篇说说SpringBoot项目启动时的原理,是按个人理解,说的不好请谅解
1.创建好项目后有个主类,上面有@SpringBootApplication注解
package com.yizheng.api;
@SpringBootApplication
public class ApiAcceptApplication {}
在idea中按住Ctrl点击进去,会看到下面两个关键注解(其他注解没有列出来)
@SpringBootConfiguration //该类为配置类
@EnableAutoConfiguration //启动自动配置
public @interface SpringBootApplication {}
从 @EnableAutoConfiguration 点进去,又有两个关键的注解,这两个注解就是SpringBoot项目启动时自动配置的核心
//扫描主类架包及以下所有子类到容器
@AutoConfigurationPackage
//把符合条件的组件自动配置到容器
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {}
2. 扫描主类架包及以下所有子类到容器 @AutoConfigurationPackage
从@AutoConfigurationPackage点进去,看到@Import导入了一个Registrar.class
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}
点击 Registrar.class,看到 registerBeanDefinitions方法,猜测是把一些bean导入到容器中
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
}
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
}
}
在 registerBeanDefinitions方法处打一个端点,可以看到 getPackageName()返回的是 @SpringBootApplication 所在主类的 package 名,然后springboot把该架包和以下子包的所有组件导入到容器,和以前的SpringMVC手动扫描组件一样,只不过在SpringBoot中变为自动扫描了,所以我们在该 package下添加的控制器能对外提供服务
3.把符合条件的组件自动配置到容器@Import({AutoConfigurationImportSelector.class})
导入了 AutoConfigurationImportSelector.class,点进去可看到 selectImports()方法,该方法返回String数组,调试下面的代码,看到系统自动加载了110个自动配置类,最后返回29个类是符合条件的
原理:项目根据元数据加载所有依赖jar组件的 META-INF/spring.factories 文件中的 org.springframework.boot.autoconfigure.EnableAutoConfiguration 属性的值,下图右边区域有很多很多,这些就是SpringBoot封装好的自动配置类,搜索 WebMvcAutoConfiguration,可以点进去,看到这些代码是以前SpringMVC时需要手动配置的,现在被SpringBoot自动写好了
以Redis为例,如果引用了Redis,那么也会加载 META-INF/spring.factories 文件中的 org.springframework.boot.autoconfigure.EnableAutoConfiguration 属性的值,里面一个 org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
看RedisAutoConfiguration的源码,
- 1.@Configuration 表示该类是配置类
- 2.ConditionalOnClass({RedisOperations.class}) 表示该类需要有RedisOperations
- 3.EnableConfigurationProperties({RedisProperties.class}) 表示启动自动配置属性,把application.properties中的属性值映射到 RedisProperties.class 类的属性上
- 4.还会导入一些配置类
```java
@Configuration
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
public 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
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
里面的代码表示会往容器中添加一个 bean,条件是容器中没有 redisTemplate bean存在,如果我们自己配置了 redisTemplate bean,则此bean不会添加到容器,有了此默认的bean后,只要在项目中
@Autowired
RedisTemplate redisTemplate;
就可以使用redis的功能了
以上就是SpringBoot启动时自动配置的原理,如果我们要使用相关组件,只要添加好对应的依赖,然后在 application.properties中添加相关配置即可,如果不知道怎么配置,可以点击到 xxxxAutoConfiguration中查看xxxxProperties类中查看
自行扩展:可以添加自定义配置的 bean 到容器,来替代默认的配置就可以扩展了