@SpringBootApplication注解源码学习

@SpringBootApplication

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {}

@ComponentScan

这个注解作用:排除或者加载或者自定义过滤规则将自定义的类,加入到Spring容器中

@EnableAutoConfiguration

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

重点是:
在这里插入图片描述

AutoConfigurationImportSelector 类

这个类的父类的父类是:ImportSelector。主要 接口是 selectImports。也就是说,重点看 AutoConfigurationImportSelector#selectImports

看方法:

	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
	// 是否开启自动注入,否的话,返回一个空数组
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		// 获取要 被spring 容器,管理的javaBean。先从 META-INF/spring.factories 加载之后,经过一系列操作,完成 Spring容器的初始化
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

getAutoConfigurationEntry 方法

Entry–中文,入口的意思

/**
	 * Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata}
	 * of the importing {@link Configuration @Configuration} class.
	 * @param annotationMetadata the annotation metadata of the configuration class
	 * @return the auto-configurations that should be imported
	 */
	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		// 1-获取注解属性,若获得的是null,将抛出异常
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		//2-去得到 下META-INF/spring.factories 定义的类实例(一般较多,需要经过后续去重,去排除,过滤等操作)
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		//3- 去重
		configurations = removeDuplicates(configurations);
		//4-得到要排除的集合
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		//5-检查排除的类
		checkExcludedClasses(configurations, exclusions);
		//5-去掉排除的类
		configurations.removeAll(exclusions);
		//6-过滤。重点
		configurations = getConfigurationClassFilter().filter(configurations);
		//7-
		fireAutoConfigurationImportEvents(configurations, exclusions);
		//8-
		return new AutoConfigurationEntry(configurations, exclusions);
	}

1-getAttributes方法

protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
		String name = getAnnotationClass().getName();
		AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
		Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
				+ " annotated with " + ClassUtils.getShortName(name) + "?");
		return attributes;
	}

2-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类
这个是:读取,spring.factories文件,并实例化,最终要放到IOC容器中
把这jar 下的 META-INF/spring.factories,key = EnableAutoConfiguration的进行实例化!

在这里插入图片描述

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
		ClassLoader classLoaderToUse = classLoader;
		if (classLoaderToUse == null) {
			classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
		}
		String factoryTypeName = factoryType.getName();
		return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
	}

	private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
		Map<String, List<String>> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		result = new HashMap<>();
		try {
			Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
			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();
					String[] factoryImplementationNames =
							StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
					for (String factoryImplementationName : factoryImplementationNames) {
						result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
								.add(factoryImplementationName.trim());
					}
				}
			}

			// Replace all lists with unmodifiable lists containing unique elements
			result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
					.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
			cache.put(classLoader, result);
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
		return result;
	}

6-过滤

点进去方法

List<String> filter(List<String> configurations) {
			long startTime = System.nanoTime();
			String[] candidates = StringUtils.toStringArray(configurations);
			boolean skipped = false;
			for (AutoConfigurationImportFilter filter : this.filters) {
				// 重点:看autoConfigurationMetadata
				boolean[] match = filter.match(candidates, this.autoConfigurationMetadata);
				for (int i = 0; i < match.length; i++) {

是个内部类。看构造器
去load “META-INF/spring-autoconfigure-metadata.properties”; 这个文件的内容
在这里插入图片描述
这个文件很大。
举个例子
在这里插入图片描述

// configurations 在过滤之前是 270个 。过滤之后,只有 120个了
configurations = getConfigurationClassFilter().filter(configurations);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值