springboot的自动装配在springboot autoconfigure子项目中完成。
从springboot 入口注解开始
@SpringBootApplication
点进去能看到有一个 @EnableAutoConfiguration 注解。
@EnableAutoConfiguration public @interface SpringBootApplication
继续点击EnableAutoConfiguration注解。
@Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {
@Import注解引入了一个AutoConfigurationImportSelector类型的bean。继续点击AutoConfigurationImportSelector,进入之后找到方法getCandidateConfigurations().
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), 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; }
断言的意思:在META-INF/spring.factories下没发现配置类。配置类的配置是在META-INF/spring.factories文件下的。找到springboot autoconfigure 项目下的META-INF/spring.factories文件。
打开配置文件(贴部分自动装配的代码):这里需要自动装配的类配置。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=/ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration
到这里应该已经理解到一些了,spring将需要自动装配的类写在META-INF/spring.factories文件里面,再启动的时候去读取需要配置的类,并进行自动装配。
跟踪代码:loadFactoryNames方法
SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); }
查看loadSpringFactories方法,贴个截图,正是去META-INF/spring.factories读取配置。
回到getCandidateConfigurations方法,结合spring ioc的加载流程理解。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); return configurations; }
找到debug模式下的调用流程图
refresh 》 处理bean工厂的后处理器 》 bean定义注册器后处理器 》 解析配置类 》 处理Import注解引入的AutoConfigurationImportSelector 》 读取META-INF/spring.factories下申明的配置类。
在bean定义扫描的时候,去META-INF/spring.factories这个文件里面读取需要自动装配的配置类,并将其添加到bean定义中。
在META-INF/spring.factories有申明redis自动装载,以redis为例讲一讲。
@Configuration @ConditionalOnClass(RedisOperations.class) @EnableConfigurationProperties(RedisProperties.class) @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }) public class RedisAutoConfiguration
@Configuration注解,这个类是一个配置类
@EnableConfigurationProperties(RedisProperties.class) 引用RedisProperties这个属性类
再看RedisProperties这个类
@ConfigurationProperties(prefix = "spring.redis") public class RedisProperties {
@ConfigurationProperties(prefix = "spring.redis")这一行,spring.redis很熟悉,就是spring boot配置文件中对redis的配置,如果有就覆盖,没有就使用默认的参数配置。
以redis举例
1.一个约定好的配置类RedisProperties。
2.一个配置类RedisAutoConfiguration,在配置类中以@Bean注解方式返回redistemplate
@Bean @ConditionalOnMissingBean(name = "redisTemplate") public RedisTemplate<Object, Object> redisTemplate( RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); return template; }
3.@SpringBootApplication注解》@EnableAutoConfiguration》@Import(AutoConfigurationImportSelector.class)
4.spring加载ioc在处理bean工厂后处理器的步骤,解析配置类。处理
@Import注解。AutoConfigurationImportSelector实现了DeferredImportSelector接口,并且重写了selectImports。在selectImports调用了getCandidateConfigurations。getCandidateConfigurations完成加载自动加载配置类。返回,这个时候还是bean定义。