共计 8759 个字符,预计需要花费 22 分钟才能阅读完成。
1、Spring Boot 自动装配原理
依赖 @Enable 模块驱动设计模式,@EnableAutoConfiguration 必然会“@Import”ImportSelector 或 ImportBeanDefinitionRegister 的实现类, 查看源码:
@Target(ElementType.TYPE) | |
@Retention(RetentionPolicy.RUNTIME) | |
@Documented | |
@Inherited | |
@AutoConfigurationPackage | |
@Import(AutoConfigurationImportSelector.class) | |
public @interface EnableAutoConfiguration {......} |
其中 AutoConfigurationImportSelector 就是 @EnableAutoConfiguration 所需 ”@Import” 的 DeferredImportSelector 实现类,由于 DeferredImportSelector 作为 ImportSeldector 的子接口,所以组件自动装配逻辑均在 selectImports 方法中.
源码:
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, | |
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { | |
...... | |
// 根据 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 读取侯选装配组件
源码:
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, ) { ClassLoader classLoaderString factoryTypeName = factoryType.getName(); | |
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList()); | |
} | |
// 装载 Spring Factories 工厂机制 | |
private static Map<String, List<String>> loadSpringFactories() { 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 排除自动装配组件
源码:
// 获取要排除的自动装配组件 | |
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 过滤自动装配组件
源码:
// 获取要过滤的自动装配组件 | |
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 文件如下:
<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、新建格式化接口
public interface Formatter {String format(Object obj); | |
} |
2.3、实现接口
public class DefaultFormatter implements Formatter {public String format(Object obj) {return String.valueOf(obj); | |
} | |
} |
2.4、实现 DefaultFormatter 自动装配
public class FormatterAutoConfiguration { | |
public Formatter defaultFormatter(){return new DefaultFormatter();} | |
} |
2.5、在 META-INF/spring.factories 资源声明 FormatterAutoConfiguration
# FormatterAutoConfiguration 自动装配声明 | |
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ | |
com.tyschool.autoconfigure.config.FormatterAutoConfiguration |
2.6、构建 Spring Boot Starter
mvn -Dmaven.test.skip -U clean install
2.7、添加 formatter-spring-boot-starter 依赖
<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、新建引导类
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();} | |
} |
正文完
星哥玩云-微信公众号
