写这篇博客的原因
- 自动装配是spring boot核心功能/特点/优点
自动装配是什么
我们添加jar依赖时,spring boot自动为我们配置一些组件的相关配置,使得我们仅用少量的配置甚至是不用配置就可以直接使用组件。
思想
我们添加依赖后,spring boot通过是否包含某个组件类等方式,推断是否需要自动配置这个组件。
实现 & 源码分析
@EnableAutoConfiguration
- @EnableAutoConfiguration注解的含义即开启自动装配
- 大家可能会有疑问,自己的spring boot项目没有用到@EnableAutoConfiguration注解,为什么也可以使用自动装配功能?因为,启动类使用用了@SpringBootApplicationٖ注解,@SpringBootApplicationٖ注解是由@SpringBootConfiguration、@ComponentScan和@EnableAutoConfiguration三个注解复合而成,无需我们显式使用@EnableAutoConfiguration注解。
- @EnableAutoConfiguration注解是由@AutoConfigurationPackage和@Import({AutoConfigurationImportSelector.class})两个注解复合而成
- @AutoConfigurationPackage注解是@Import({Registrar.class})的封装
- @Import作用是导入组件,@Import({Registrar.class})就是导入Registrar.class,
- Registrar类将启动类所在包及其所有子包下的组件(例如@Entity)扫描到spring容器中,而@ComponentScan是扫描的@Component注解(包括其派生的注解@Controller/@Service/@Component/@Repository)
- @Import({AutoConfigurationImportSelector.class})注解即是导入AutoConfigurationImportSelector.class
- @AutoConfigurationPackage注解是@Import({Registrar.class})的封装
AutoConfigurationImportSelector
直译类名:自动配置导入筛选器,见名知意:将“自动配置”的配置筛选并导入到系统中,方式如下:
- 通过SpringFactoriesLoader加载META-INF/spring.factories中的自动配置类
- 通过AutoConfigurationMetadataLoader加载META-INF/spring-autoconfigure-metadata.properties文件中自动配置类的自动装配条件
- 自动配置类进行去重,去掉注解的排除属性排除的自动配置类,使用自动装配条件过滤自动配置类
源码分析:
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
private static class AutoConfigurationGroup
implements DeferredImportSelector.Group, BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {
@Override
// 入口方法
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
() -> String.format("Only %s implementations are supported, got %s",
AutoConfigurationImportSelector.class.getSimpleName(),
deferredImportSelector.getClass().getName()));
//获取自动装配的配置
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(annotationMetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//从配置文件加载自动装配类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
//自动装配类去重
configurations = removeDuplicates(configurations);
//排除 我们配置的 ‘需要排除的’ 自动配置类,即:
// @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
// @SpringBootApplication(excludeName ={"org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration"})
// 等
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
//根据自动配置条件,过滤无需启用的自动配置类
// 1. 通过AutoConfigurationMetadataLoader加载META-INF/spring-autoconfigure-metadata.properties文件中自动装配条件
// 形式自动装配类.条件=值
// org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration$MessagingTemplateConfiguration.ConditionalOnClass=org.springframework.amqp.rabbit.core.RabbitMessagingTemplate
// 常见的自动装配条件如:某个类是否存在,某个bean是否存在,配置文件的某个配置项是否存在等
// 2. 使用ConfigurationClassFilters过滤器链使用过滤条件过滤自动配置类
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//通过SpringFactoriesLoader加载META-INF/spring.factories中的自动配置类,如下所示
// # Auto Configure
// org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
// org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
// org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
// org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
// 省略...
//configurations中每个元素就是如org.springframework.boot.autoconfigure.aop.AopAutoConfiguration这样的自动配置类的类全名,共有100多个
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;
}
}
启动流程中关于自动装配的步骤
- 启动类main方法调用SpringApplication.run(BootApplication.class, args);
@SpringBootApplication
public class BootApplication {
public static void main(String[] args) {
SpringApplication.run(BootApplication.class, args);
}
}
- SpringApplication.run(BootApplication.class, args)经过调用链,调用到本类的实例方法run(String… args)
public class SpringApplication {
public ConfigurableApplicationContext run(String... args) {
//省略...
ConfigurableApplicationContext context = null;
//省略...
//创建spring上下文,最终调用到ApplicationContextFactory函数式接口,
// 如果是SERVLET应用就new AnnotationConfigServletWebServerApplicationContext()
// 如果是REACTIVE应用就new AnnotationConfigReactiveWebServerApplicationContext()
// 都不是则new AnnotationConfigApplicationContext()
context = createApplicationContext();
//省略...
//创建上下文,最终会调用到AbstractApplicationContext.refresh()方法,这个方法是spring上下文初始化的核心方法
context = createApplicationContext();
//刷新上下文
refreshContext(context);
//省略...
}
}
- AbstractApplicationContext.refresh(),这个方法是spring上下文启动的核心流程,也是"自动装配的总体流程"。
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//省略...
// Tell the subclass to refresh the internal bean factory.
// 初始化BeanFactory-默认实现是DefaultListableBeanFactory
// 1. 使用SAX对xml文件进行读取,转化为Document
// 2. 对xml中的各种标签进行解析
// 2.1 如果是bean标签,将其解析为BeanDefition,并注册到容器中,一般是DefaultListableBeanFactory.beanDefinitionMap
// 2.2 如果是包扫描标签,则使用ComponentScanBeanDefinitionParser解析
// 2.2.1 解析的注解类型为:@Component及其子注解(@Repository、@Service、@Controller、@Configuration)
// 2.2.2 将包扫描路径转化为绝对路径,通过字节流读取包扫描路径下的.class文件
// 2.2.3 通过ClassReader及其他组件直接解析.class文件的内容为BeanDefition,使用asm技术按JVM规范解析.class文件
// 2.2.4 将上一步解析得到的BeanDefition注册到容器中,一般是DefaultListableBeanFactory.beanDefinitionMap
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//省略...
// Invoke factory processors registered as beans in the context.
// invokeBeanFactoryPostProcessors()方法是执行所有BeanFactory的后置处理器
// * 即执行实现BeanDefinitionRegistryPostProcessor接口的实现类,
// * 这样就会执行到ConfigurationClassPostProcessor#processConfigBeanDefinitions()
// * 直译:配置类(@Configuration注解的类)后置处理器#处理配置Bean定义信息
// * 该方法委托ConfigurationClassParser#doProcessConfigurationClass()对配置Bean进行解析
// * 该方法可以解析@Component,@PropertySource,@ComponentScan, @Import,@ImportResource,@Bean等注解
invokeBeanFactoryPostProcessors(beanFactory);
//省略...
// Instantiate all remaining (non-lazy-init) singletons.
//通过BeanDefinitions初始化单例非懒加载的bean
// 原型Bean的初始化时机:每次通过BeanFactory.getBean()时新生成一个
// 懒加载Bean的初始化时机:延迟使用时加载
//通过自动配置Bean实例化,完成自动配置功能
finishBeanFactoryInitialization(beanFactory);
//省略...
}
}
- ConfigurationClassPostProcessor#processConfigBeanDefinitions()
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, ApplicationStartupAware, BeanClassLoaderAware, EnvironmentAware {
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//省略...
// Parse each @Configuration class
// 注解类解析器会解析每一个@Configuration注解的类
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
//注解类解析器解析,会执行到ConfigurationClassParser#parse()
parser.parse(candidates);
//省略...
}
while (!candidates.isEmpty());
//省略...
//最终得到了注解bean定义
}
}
- ConfigurationClassParser#parse()
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, ApplicationStartupAware, BeanClassLoaderAware, EnvironmentAware {
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
//最终调用到ConfigurationClassPostProcessor.DeferredImportSelectorGrouping#getImports()
this.deferredImportSelectorHandler.process();
}
private static class DeferredImportSelectorGrouping {
public Iterable<Group.Entry> getImports() {
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
// 调用到AutoConfigurationImportSelector.AutoConfigurationGroup#process()
// AutoConfigurationImportSelector类我们在上面已经分析过了
this.group.process(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getImportSelector());
}
// 调用到AutoConfigurationImportSelector.AutoConfigurationGroup#selectImports()
// AutoConfigurationImportSelector类我们在上面已经分析过了
return this.group.selectImports();
}
}
}