1、Spring Boot自动装配原理
依赖@Enable模块驱动设计模式,@EnableAutoConfiguration必然会“@Import” ImportSelector或ImportBeanDefinitionRegister的实现类,查看源码:
代码语言:javascript复制@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
......
}
其中AutoConfigurationImportSelector就是@EnableAutoConfiguration 所需"@Import"的DeferredImportSelector实现类,由于DeferredImportSelector作为ImportSeldector的子接口,所以组件自动装配逻辑均在selectImports方法中.
源码:
代码语言:javascript复制public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
......
@Override
//根据autoConfigurationMetadata条件执行过滤
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;
}
//获取@EnableAutoConfiguration标注类的元信息
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);
//根据autoConfigurationMetadata条件执行过滤
configurations = filter(configurations, autoConfigurationMetadata);
//自动装配的导入事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
解析:
- AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader);加载自动装配的元信息
- AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);获取自动装配信息
- AnnotationAttributes attributes = getAttributes(annotationMetadata);获取@EnableAutoConfiguration标注类的元信息
- List configurations = getCandidateConfigurations(annotationMetadata, attributes);获取自动装配的候选类名集合
- configurations = removeDuplicates(configurations);移除重复对象
- Set exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions);获取自动装配黑名单
- configurations = filter(configurations, autoConfigurationMetadata);根据autoConfigurationMetadata条件执行过滤
- fireAutoConfigurationImportEvents(configurations, exclusions);自动装配的导入事件
1.1、@EnableAutoConfiguration读取侯选装配组件
源码:
代码语言:javascript复制 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;
}
//获取Spring Factories加载工厂类
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
//通过名字讲行加载
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
//装载Spring Factories工厂机制
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
//从缓存中获取
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
//搜索指定Classpath下所有的META-INF/spring.factories资源内容
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
//循环遍历spring.factories资源内容
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
//将资源内容制作为properties文件
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
//合并为一个key为接口全类名,value是实现类全类名列表
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
//接口全类名
String factoryTypeName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; var11) {
//实现类全类名
String factoryImplementationName = var9[var11];
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
//放入缓存
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
1.2、@EnableAutoConfiguration排除自动装配组件
源码:
代码语言:javascript复制 //获取要排除的自动装配组件
protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//用于存储排除名单
Set<String> excluded = new LinkedHashSet<>();
//添加排除类,spring.autoconfigure.exclude
excluded.addAll(asList(attributes, "exclude"));
//添加排除类名,spring.autoconfigure.excludeName excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
//添加所有的自动装配排除集合,用于后面检查类名集合是否合法
excluded.addAll(getExcludeAutoConfigurationsProperty());
return excluded;
}
1.3、@EnableAutoConfiguration过滤自动装配组件
源码:
代码语言:javascript复制 //获取要过滤的自动装配组件
private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
long startTime = System.nanoTime();
//将自动装配类名转化为字符串数组
String[] candidates = StringUtils.toStringArray(configurations);
boolean[] skip = new boolean[candidates.length];
boolean skipped = false;
for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
invokeAwareMethods(filter);
//查检是否匹配
boolean[] match = filter.match(candidates, autoConfigurationMetadata);
for (int i = 0; i < match.length; i ) {
//如果需要过滤
if (!match[i]) {
skip[i] = true;
candidates[i] = null;
skipped = true;
}
}
}
//如果不需要过滤,直接返回
if (!skipped) {
return configurations;
}
List<String> result = new ArrayList<>(candidates.length);
//如果需要过滤,将过滤后的对象放入result
for (int i = 0; i < candidates.length; i ) {
if (!skip[i]) {
result.add(candidates[i]);
}
}
if (logger.isTraceEnabled()) {
int numberFiltered = configurations.size() - result.size();
logger.trace("Filtered " numberFiltered " auto configuration class in "
TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) " ms");
}
//返回过滤后的类名集合
return new ArrayList<>(result);
}
//获取由所有ImportFilters集合
protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
}
2、 自定义Spring Boot Starter
2.1、 新添加Maven工程
pom.xml文件如下:
代码语言:javascript复制<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tyschool</groupId>
<artifactId>formatter-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.2.6.RELEASE</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>
2.2、 新建格式化接口
代码语言:javascript复制public interface Formatter {
String format(Object obj);
}
2.3、 实现接口
代码语言:javascript复制public class DefaultFormatter implements Formatter {
public String format(Object obj) {
return String.valueOf(obj);
}
}
2.4、 实现DefaultFormatter自动装配
代码语言:javascript复制@Configuration
public class FormatterAutoConfiguration {
@Bean
public Formatter defaultFormatter(){
return new DefaultFormatter();
}
}
2.5、 在META-INF/spring.factories资源声明FormatterAutoConfiguration
代码语言:javascript复制# FormatterAutoConfiguration 自动装配声明
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.tyschool.autoconfigure.config.FormatterAutoConfiguration
2.6、 构建Spring Boot Starter
代码语言:javascript复制 mvn -Dmaven.test.skip -U clean install
2.7、 添加formatter-spring-boot-starter依赖
代码语言:javascript复制 <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.2.6.RELEASE</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.tyschool</groupId>
<artifactId>formatter-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
2.8、 新建引导类
代码语言:javascript复制@SpringBootApplication
public class FormatterBootStrap {
public static void main(String[] args) {
//创建Spring 上下文
ConfigurableApplicationContext context = new SpringApplicationBuilder(FormatterBootStrap.class)
.web(WebApplicationType.NONE)
.run(args);
Map<String, Object> map = new HashMap<String, Object>();
map.put("name","tyschool");
//获取bean
Formatter formatter = context.getBean(Formatter.class);
//格式化数据并输出
System.out.println(formatter.format(map));
context.close();
}
}