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;
}
/**
* Return the class used by {@link SpringFactoriesLoader} to load configuration
* candidates.
* @return the factory class
*/
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
Spring Boot已经成为Java后端开发标配开发框架,无论是工作,还是面试当中,不得不掌握的技术。说起Spring Boot笔者认为最重要的功能非自动配置莫属了。
Spring Boot的出现得益于“习惯优于配置”(COC)的理念,没有繁琐的配置、难以集成的内容(大多数流行第三方技术都被集成),这是基于Spring 4.x以上的版本提供的按条件配置Bean的能力。有了springboot的自动配置的功能,我们可以快速的开始一个项目。
本文基于Spring Boot 2.3.3.RELEASE 源码进行分析。
工作原理
Spring Boot的启动类上有一个@SpringBootApplication注解,这个注解是Spring Boot项目必不可少的注解。
我们先看看@SpringBootApplication注解
请注意其中一个非常关键的注解:@EnableAutoConfiguration
该注解的关键功能由@Import提供,其导入的AutoConfigurationImportSelector的selectImports()方法通过SpringFactoriesLoader.loadFactoryNames()扫描所有具有
META-INF/spring.factories
的jar包下面key是EnableAutoConfiguration全名的,所有自动配置类。AutoConfigurationImportSelector核心代码如下:
核心逻辑在 getCandidateConfigurations方法中,如下:
这里会调用 SpringFactoriesLoader#loadFactoryNames方法去加载
META-INF/spring.factories
文件,这里key是EnableAutoConfiguration类的全类名。SpringFactoriesLoader 何许人也?它其实是Spring框架的一个 SPI实现,借鉴自JDK中的
java.util.ServiceLoader
。我们可以看看spring-boot-autoconfigure-2.3.3.RELEASE.jar 文件结构
该jar包里面就有META-INF/spring.factories文件,其内容如下:
这个spring.factories文件是一组一组的key=value的形式,其中一个key是EnableAutoConfiguration类的全类名,而它的value是一个xxxxAutoConfiguration的类名的列表,这些类名以逗号分隔。
@EnableAutoConfiguration注解通过@SpringBootApplication被间接的标记在了Spring Boot的启动类上。在SpringApplication.run(...)的内部就会执行selectImports()方法,找到所有JavaConfig自动配置类的全限定名对应的class,然后将所有自动配置类加载到Spring容器中。
SpringApplication
SpringApplication.run方法如下:
接着,我们来看看run方法:
SpringApplication.run()方法是怎么调到selectImports()方法的呢?
其加载过程大概是这样的: SpringApplication.run(...)方法
----> SpringApplication.refreshContext()方法 ----> SpringApplication.createApplicationContext()方法(AnnotationConfigApplicationContext类) ----> AbstractApplicationContext.refresh()方法
----> invokeBeanFactoryPostProcessors(...)方法 ----> PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(...) 方法 ----> ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(..)方法 ----> AutoConfigurationImportSelector.selectImports
该方法会找到自动配置的类,并给打了@Bean注解的方法创建对象。
postProcessBeanDefinitionRegistry方法是最核心的方法,它负责解析@Configuration、@Import、@ImportSource、@Component、@ComponentScan、@Bean等,完成bean的自动配置功能。