springboot的自动装配
SpringBootApplication 本质上是由 3 个注解组成,分别是
1. @Configuration
2. @EnableAutoConfiguration
3. @ComponentScan
@Configuration是 JavaConfig形式的基于 Spring IOC 容器的配置类使用的一种注解。
@ComponentScan 这个注解是大家接触得最多的了,相当于 xml 配置文件中的<context:component-scan>。 它的主要作用就是扫描指定路径下的标识了需要装配的类,自动装配到 spring 的 Ioc 容器中。
@EnableAutoConfiguration为了实现自动装配
@EnableAutoConfiguration
本质上来说,其实 EnableAutoConfiguration 会帮助springboot 应用把所有符合@Configuration 配置都加载到当前 SpringBoot 创建的 IoC 容器,而这里面借助了Spring 框架提供的一个工具类 SpringFactoriesLoader 的支持。以及用到了 Spring 提供的条件注解@Conditional,选择性的针对需要加载的 bean 进行条件过滤
@Import(AutoConfigurationImportSelector.class)将第三方提供的 bean 的配置类AutoConfigurationImportSelector导入IOC。
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
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);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
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;
}
通过上面源码的一步步深入可以定位到
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
SpringFactoriesLoader这个工具类和JDK的SPI原理一样,不过它比 SPI 更好的点在于不会一次性加载所有的类,而是根据 key 进行加载。
SpringFactoriesLoader 的 作 用 是 从classpath/META-INF/spring.factories 文件中,根据 key 来加载对应的类到 spring IoC 容器中。
先扫描 spring-autoconfiguration-metadata.properties文件,最后在扫描 spring.factories 对应的类时,会结合前面的元数据进行过滤,过滤的原因是很多的@Configuration 其实是依托于其他的框架来加载的,如果当前的 classpath 环境下没有相关联的依赖,则意味着这些类没必要进行加载,所以,通过这种条件过滤可以有效的减少@configuration 类的数量从而降低SpringBoot 的启动时间。
自动装配的Demo
git地址:https://gitee.com/pengzhang_master/spring-boot-enableauto
项目结构
core-test模块
package core;
public class Core {
public String study(){
System.out.println("good good study, day day up");
return "hhhhhhhh";
}
}
package core;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Config {
@Bean
public Core Core(){
return new Core();
}
}
spring.factories下添加自动装配的类
org.springframework.boot.autoconfigure.EnableAutoConfiguration=core.Config
enableauto模块
此模块是springboot项目
package com.example.enableauto;
import core.Core;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class EnableautoApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(EnableautoApplication.class, args);
System.out.println(run.getBean(Core.class).study());
}
}
测试