组团学

深入Spring Boot自动装配

阅读 (3244227)

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 { ...... @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读取侯选装配组件

源码:

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排除自动装配组件

源码:

//获取要排除的自动装配组件 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自动装配

@Configuration public class FormatterAutoConfiguration { @Bean 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、 新建引导类

@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(); } }
需要 登录 才可以提问哦