spring-boot源码学习笔记(1)- springboot 实现自动装配的原理


原理概述

通过注解@SpringBootApplication 引入注解@EnableAutoConfiguration, @EnableAutoConfiguration的作用是:将 classpath目录下的META-INF/spring.factories文件中的key为org.springframework.boot.autoconfigure.EnableAutoConfiguration所有的类加载到Spring的ioc容器中,从而实现在动装配

提示:以下是本篇文章正文内容,下面案例可供参考

一、@EnableAutoConfiguration说明

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
....
}

以上代码可以看出@EnableAutoConfiguration由@AutoConfigurationPackage、@Import 两个注解组成,这里最为关键的是@Import(AutoConfigurationImportSelector.class),借助AutoConfigurationImportSelector可以将所有满足条件的
@Configuration配置类都加载到当前SpringBoot的IoC容器中

二、AutoConfigurationImportSelector说明

温馨提示:所有实现ImportSelector的类,都会在启动时被ConfigurationClassParser中的processImports进行实例化,并执行selectImports方法。

## selectImports 从AutoConfigurationImportSelector代码中可以看到selectImports方法,该方法获取

	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

getAutoConfigurationEntry 方法

从上述代码再进入getAutoConfigurationEntry 方法

	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		// 获取注解的属性值
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		// 获取所有候选配置类EnableAutoConfiguration
        // 使用了内部工具使用SpringFactoriesLoader,查找classpath上所有jar包中的
        // META-INF\spring.factories,找出其中key为
        // org.springframework.boot.autoconfigure.EnableAutoConfiguration 
        // 的属性定义的工厂类名称。
        // 虽然参数有annotationMetadata,attributes,但在 AutoConfigurationImportSelector 的
        // 实现 getCandidateConfigurations()中,这两个参数并未使用
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		        // 应用过滤器AutoConfigurationImportFilter,
        // 对于 spring boot autoconfigure,定义了一个需要被应用的过滤器 :
        // org.springframework.boot.autoconfigure.condition.OnClassCondition,
        // 此过滤器检查候选配置类上的注解@ConditionalOnClass,如果要求的类在classpath
        // 中不存在,则这个候选配置类会被排除掉
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

getCandidateConfigurations

从上述代码再进入getCandidateConfigurations方法

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

SpringFactoriesLoader.loadFactoryNames() 方法

其中常量 FACTORIES_RESOURCE_LOCATION = “META-INF/spring.factories”; 先从缓存cache中获取,当为空时再去META-INF/spring.factories中加载(由于在SpringApplication 实例化时,会加载监听器、初始化器,而加载这些时会去加载spring.factories,此时cache不会为空)

	public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
	private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
		MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		try {
			Enumeration<URL> urls = (classLoader != null ?
					classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			result = new LinkedMultiValueMap<>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryTypeName = ((String) entry.getKey()).trim();
					for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
						result.add(factoryTypeName, factoryImplementationName.trim());
					}
				}
			}
			cache.put(classLoader, result);
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}

参考

https://www.despairyoke.com/2018/12/05/2018/2018-12-05-spring-boot-factories/

https://blog.csdn.net/zxc123e/article/details/80222967

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值