掘金链接:https://juejin.cn/post/7177731868471590968/
一 Spring boot 组件自动装配
在Spring boot框架中,我们可以不必配置xml文件,就能完成Bean注入IOC的动作。这在之前的Spring是通过xml配置来说明要装配的组件,Spring boot为了简化开发人员的配置工作,遵循"约定大于配置,配置大于编码"原则,
通过约定来实现IOC的注入,通过默认配置来代替常规的配置,从而简化了开发人员的配置和开发过程,提升研发效率。
二 Spring boot 如何实现自动装配
整体流程是@EnableAutoConfiguration中的实现类扫描“classpath下即Pom依赖”中所有包含/META-INF/spring.factories的包,并根据其xxxAutoConfiguration和/META-INF/spring-autoconfigure-metadata.properties中的条件判断来决定是否进行自动装配。
主类设置如下
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
@EnableScheduling
@EnableConfigurationProperties({GlobalConfig.class})
public class ProxyApplication {
public static void main(String[] args) {
SpringApplication.run(ProxyApplication.class, args);
}
}
我们知道,注解SpringBootApplication是一系列注解的组合,其中包含@EnableAutoConfiguration注解
@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) })
public @interface SpringBootApplication {}
而根据@Enable模块驱动设计模式(即Import的类被@Configuration注解或实现ImportSelector接口,可实现注入),@EnableAutoConfiguration必然Import了“实现ImportSelector接口的实现类”,并实现其selectImport方法
// 1. Import了AutoConfigurationImportSelector类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}
//2. 实现了DeferredImportSelector接口,并重写selectImports方法
public class AutoConfigurationImportSelector
implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
BeanFactoryAware, EnvironmentAware, Ordered {
}
//3. 继承ImportSelector接口
public interface DeferredImportSelector extends ImportSelector {}
基于@Enable和selectImports装配的方式我们知道,通过selectImports方法返回需要装配的对象数组,整个搜索流程如下:
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);//1. 获取classpath下自动加载配置的元数据
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(
autoConfigurationMetadata, annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntry(
AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);//2.获取注解的属性信息
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);//3. 获取classpath下所有enable的候装配组件
configurations = removeDuplicates(configurations); //4. 组件去重
Set<String> exclusions = getExclusions(annotationMetadata, attributes);//5. exclude去重
checkExcludedClasses(configurations, exclusions);//6. 组件去exclude
configurations.removeAll(exclusions);//6. 组件去exclude
configurations = filter(configurations, autoConfigurationMetadata);//7. 组件过滤
fireAutoConfigurationImportEvents(configurations, exclusions);//8. 触发自动装配监听
return new AutoConfigurationEntry(configurations, exclusions);
}
整体流程:
1. 获取自动加载配置的元数据:主要是获取classpath下所有META-INF/spring-autoconfigure-metadata.properties中的配置信息,该文件里面配置的作用等同于在xxxAutoConfiguration上面的@ConditionalOnClass等注解,这么做的好处就是参考官网说明(Spring Boot uses an annotation processor to collect the conditions on auto-configurations in a metadata file (META-INF/spring-autoconfigure-metadata.properties). If that file is present, it is used to eage