Giter Site home page Giter Site logo

Comments (8)

zyllt avatar zyllt commented on August 11, 2024

该类的核心方法就是selectImports,下面是源码和一些自己的阅读注释,英文渣可能不准确

	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		/**
		 * {@link EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY} = false时此自动配置不启用,默认true
		 */
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		/**
		 * 加载{@link AutoConfigurationMetadataLoader.PATH}文件(此文件是spring boot autoconfiguration模块编译时自动生成,保存所有的autoconfiguration的conditional )
		 * 在调用AutoConfigurationImportFilter被使用(OnClassCondition)
		 */
		AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
				.loadMetadata(this.beanClassLoader);
		/**
		 *  *获取{@link EnableAutoConfiguration} 属性,肯定有值
		 */
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		//获取自动配置的类名称集合,使用SpringFactoriesLoader
		List<String> configurations = getCandidateConfigurations(annotationMetadata,
				attributes);
		//去重,转set
		configurations = removeDuplicates(configurations);
		//获取需要排除的类,通过注解或者配置
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		//校验是否有无效的排除类,有的话就抛出异常 (暂时不明白这么做的意义)
		checkExcludedClasses(configurations, exclusions);
		//从需要自动配置的类中删除需要排除的类
		configurations.removeAll(exclusions);
		/**
		 * 执行 {@link AutoConfigurationImportFilter},此时也可以排除不想使用自动配置的的类
		 *
		 * 其实是触发了 {@link org.springframework.boot.autoconfigure.condition.OnClassCondition}排除了
		 * {@link org.springframework.boot.autoconfigure.condition.ConditionalOnClass} 不存在的类
		 *
		 */
		configurations = filter(configurations, autoConfigurationMetadata);
		//加载、触发 AutoConfigurationImportListener
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return StringUtils.toStringArray(configurations);
	}

from project.

zyllt avatar zyllt commented on August 11, 2024

这个方法比较简单,几个逻辑都是很容易理解的。其中比较核心的逻辑就是获取所有的@EnableAutoConfiguration类名称(使用SpringFactoriesLoader来加载,一般我们也可以这么做)

	/**
	 * Return the auto-configuration class names that should be considered. By default
	 * this method will load candidates using {@link SpringFactoriesLoader} with
	 * {@link #getSpringFactoriesLoaderFactoryClass()}.
	 * @param metadata the source metadata
	 * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
	 * attributes}
	 * @return a list of candidate configurations
	 */
	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;
	}

	/**
	 * Return the class used by {@link SpringFactoriesLoader} to load configuration
	 * candidates.
	 * @return the factory class
	 */
	protected Class<?> getSpringFactoriesLoaderFactoryClass() {
		return EnableAutoConfiguration.class;
	}

from project.

zyllt avatar zyllt commented on August 11, 2024

还有就是filter方法,该方法会验证所有的 @EnableAutoConfiguration类然后排除不符合条件的自动配置类(配置了ConditionalOnClass注解的类不存在)

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;
		//获取 AutoConfigurationImportFilter,默认是 OnClassCondition
		for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
			//调用filter的aware方法,如果存在
			invokeAwareMethods(filter);
			boolean[] match = filter.match(candidates, autoConfigurationMetadata);
			for (int i = 0; i < match.length; i++) {
				if (!match[i]) {
					skip[i] = true;
					skipped = true;
				}
			}
		}
		if (!skipped) {
			return configurations;
		}
		List<String> result = new ArrayList<>(candidates.length);
		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);
	}

from project.

zyllt avatar zyllt commented on August 11, 2024

其中默认存在的AutoConfigurationImportFilter只有OnClassCondition,通过这个filter来验证配置了注解ConditionalOnClass是否合法

	@Override
	public boolean[] match(String[] autoConfigurationClasses,
			AutoConfigurationMetadata autoConfigurationMetadata) {
		ConditionEvaluationReport report = getConditionEvaluationReport();
		//返回验证结果,这个结果的长度和autoConfigurationClasses相同,如果验证通过对应的结果为null或者ConditionOutcome.match=true
		ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses,
				autoConfigurationMetadata);
		boolean[] match = new boolean[outcomes.length];
		for (int i = 0; i < outcomes.length; i++) {
			match[i] = (outcomes[i] == null || outcomes[i].isMatch());
			if (!match[i] && outcomes[i] != null) {
				//验证不通过的输出log
				logOutcome(autoConfigurationClasses[i], outcomes[i]);
				if (report != null) {
					report.recordConditionEvaluation(autoConfigurationClasses[i], this,
							outcomes[i]);
				}
			}
		}
		return match;
	}

from project.

zyllt avatar zyllt commented on August 11, 2024
	private ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
			AutoConfigurationMetadata autoConfigurationMetadata) {
		// Split the work and perform half in a background thread. Using a single
		// additional thread seems to offer the best performance. More threads make
		// things worse
		//有个独立的线程处理一半,主线程处理一半
		int split = autoConfigurationClasses.length / 2;
		//创建StandardOutcomesResolver,并且启动一个独立线程来执行一半任务
		OutcomesResolver firstHalfResolver = createOutcomesResolver(
				autoConfigurationClasses, 0, split, autoConfigurationMetadata);

		//主线程执行StandardOutcomesResolver
		OutcomesResolver secondHalfResolver = new StandardOutcomesResolver(
				autoConfigurationClasses, split, autoConfigurationClasses.length,
				autoConfigurationMetadata, this.beanClassLoader);
		ConditionOutcome[] secondHalf = secondHalfResolver.resolveOutcomes();
		//这个实际是用thread.join()来保证独立线程任务执行完成了
		ConditionOutcome[] firstHalf = firstHalfResolver.resolveOutcomes();
		//合并2个结果
		ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
		System.arraycopy(firstHalf, 0, outcomes, 0, firstHalf.length);
		System.arraycopy(secondHalf, 0, outcomes, split, secondHalf.length);
		return outcomes;
	}

from project.

zyllt avatar zyllt commented on August 11, 2024

StandardOutcomesResolverresolveOutcomes()方法执行逻辑,其实就是验证ConditonalOnClass配置的class是否存在

		@Override
		public ConditionOutcome[] resolveOutcomes() {
			return getOutcomes(this.autoConfigurationClasses, this.start, this.end,
					this.autoConfigurationMetadata);
		}

		private ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
				int start, int end, AutoConfigurationMetadata autoConfigurationMetadata) {
			ConditionOutcome[] outcomes = new ConditionOutcome[end - start];
			for (int i = start; i < end; i++) {
				String autoConfigurationClass = autoConfigurationClasses[i];
				//从PropertiesAutoConfigurationMetadata 注解ConditionalOnClass的类,其实就是获取这个类有使用@ConditionalOnClass修饰时设置的类
				Set<String> candidates = autoConfigurationMetadata
						.getSet(autoConfigurationClass, "ConditionalOnClass");
				if (candidates != null) {
					//判断这个类是否存在,如果存在就返回null
					outcomes[i - start] = getOutcome(candidates);
				}
			}
			return outcomes;
		}

from project.

zyllt avatar zyllt commented on August 11, 2024

从以上可以看出如果想试用自动配置,首先要@EnableAutoConfiguration,然后还要配置META-INF/spring.factories ,例如

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\

from project.

zyllt avatar zyllt commented on August 11, 2024

另外还有一种编程式自动配置的方案就是使用@ImportAutoConfiguration注解。这个注解的实现方式比较简单,是通过ImportAutoConfigurationImportSelector,这个类继承了AutoConfigurationImportSelector然后重写了其获取自动配置类的部分,其他没啥变化

from project.

Related Issues (19)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.