深入Spring Boot自动装配

2022-09-15 14:01:13 浏览数 (1)

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();
    }
}

0 人点赞