SpringBoot自动装配原理
在介绍SpringBoot自动装配原理之前我们需要先看一个注解 --> SpringBootApplication
@SpringBootApplication
public class BackendApp {
public static void main(String[] args) {
SpringApplication.run(BackendApp.class, args);
}
}
我们都知道SpringBootApplication是用来声明引导类的 , 除此之外他还应用于自动装配
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
打开源码我们可以看到 , 除了元注解之外在SpringBootApplication中还提供了三种注解
- SpringBootConfigurtion --> 声明配置类
- EnableAutoConfiguration --> 自动装配
- ComponentScan --> 扫描包
那么SpringBoot自动装配就和EnableAutoConfiguration 该注解相关
@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 {};
}
在这里有两个很重要的注解
- @AutoConfigurationPackage
- @Import({AutoConfigurationImportSelector.class})
对于AutoConfigurationPackage它的作用是扫描我们在项目中自行定义的Bean(如Controller , Service , Dao层的Bean) , 其内部通过了Import导入了AutoConfigurationPackages.Registrar.class , 可以扫描项目当中的Bean
而@Import({AutoConfigurationImportSelector.class}) , 就是导入自动配置的选择器 , 该选择器会加载一个文件 , 该文件定义了很多自动配置的类
这里以RedisAutoConfiguration为列 , 我们看看都做了什么
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
public RedisAutoConfiguration() {
}
@Bean
@ConditionalOnMissingBean(
name = {"redisTemplate"}
)
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
首先我们来看一个注解 @ConditionalOnClass({RedisOperations.class})
该注解是用来判断类路径当中是否包含该字节码文件 , 简单来说就是有没有导入对应的依赖 , 如果导入了才能创建该Bean
除此之外在创建Bean的过程中还会通过
@ConditionalOnMissingBean(
name = {“redisTemplate”}
)
来判断在Bean中是否已经存在过了名为redisTemplate的注解 , 以便于开发者自行配置
==========================================================
面试官:Springboot自动配置原理
候选人:
嗯,好的,它是这样的。
在Spring Boot项目中的引导类上有一个注解@SpringBootApplication,这个注解是对三个注解进行了封装,分别是:
- @SpringBootConfiguration
- @EnableAutoConfiguration
- @ComponentScan
其中@EnableAutoConfiguration
是实现自动化配置的核心注解。
该注解通过@Import
注解导入对应的配置选择器。关键的是内部就是读取了该项目和该项目引用的Jar包的的classpath路径下META-INF/spring.factories文件中的所配置的类的全类名。
在这些配置类中所定义的Bean会根据条件注解所指定的条件来决定是否需要将其导入到Spring容器中。
一般条件判断会有像@ConditionalOnClass
这样的注解,判断是否有对应的class文件,如果有则加载该类,把这个配置类的所有的Bean放入spring容器中使用。