Springboot自动装配以及启动原理解析

一、引子

在传统的Spring项目中,需要引入大量的配置来载入相关的功能模块,实现导入相关功能作用,使项目创建和引入新功能时做了大量重复繁杂的工作。Springboot项目出现,使项目中只需引入相关功能模块的依赖包,即可使用程序相关功能。

二、自动配置类

Springboot中把相关功能的Bean放到了一个配置类中,分门别类,针对不同的场景,定义了不同的自动配置类,如:

  • ServletWebServerFactoryAutoConfiguration:配置了Servlet Web场景中所需要的一些Bean
  • TransactionAutoConfiguration:配置了事务场景中所需要的一些Bean
  • AopAutoConfiguration:配置了AOP场景中所需要的一些Bean
  • RabbitAutoConfiguration:配置了Rabbitmq场景中所需要的一些Bean 等等

使用这种结构后,SpringBoot就能让程序员更为方便的来控制某个Bean或某些Bean要不要生效,如
果某个自动配置类不生效,那该配置类中所定义的Bean则都不会生效。

三、条件注解

1 自定义条件注解 @Conditional

SpringBoot中众多的条件注解,都是基于Spring中的@Conditional来实现的。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {

	/**
	 * All {@link Condition} classes that must {@linkplain Condition#matches match}
	 * in order for the component to be registered.
	 */
	Class<? extends Condition>[] value();

}

使用自定义条件注解

public class SonnyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(ConditionalOnClass.class.getName());
        String className = (String) annotationAttributes.get("value");

        try {
            context.getClassLoader().loadClass(className);
            return true;
        } catch (ClassNotFoundException e) {
            return false;
        }
    }
}

matches方法中来定义条件逻辑:

  1. ConditionContext:表示条件上下文,可以通过ConditionContext获取到当前的类加载器、BeanFactory、
    Environment环境变量对象
  2. AnnotatedTypeMetadata:表示当前正在进行条件判断的Bean所对应的类信息,或方法信息(比如@Bean定义
    的一个Bean),可以通过AnnotatedTypeMetadata获取到当前类或方法相关的信息,从而就可以拿到条件注解的
    信息,当然如果一个Bean上使用了多个条件注解,那么在解析过程中都可以获取到,同时也能获取Bean上定义
    的其他注解信息

2 ConditionalOnClass

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {

	/**
	 * The classes that must be present. Since this annotation is parsed by loading class
	 * bytecode, it is safe to specify classes here that may ultimately not be on the
	 * classpath, only if this annotation is directly on the affected component and
	 * not if this annotation is used as a composed, meta-annotation. In order to
	 * use this annotation as a meta-annotation, only use the {@link #name} attribute.
	 * @return the classes that must be present
	 */
	Class<?>[] value() default {};

	/**
	 * The classes names that must be present.
	 * @return the class names that must be present.
	 */
	String[] name() default {};

}

主要作用注解 @Conditional(OnClassCondition.class) ,使用了 OnClassCondition 类,接下来我们看这个类做了什么。

@Order(Ordered.HIGHEST_PRECEDENCE)
class OnClassCondition extends FilteringSpringBootCondition {

	@Override
	protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
			AutoConfigurationMetadata autoConfigurationMetadata) {
		// Split the work and perform half in a background thread if more than one
		// processor is available. Using a single additional thread seems to offer the
		// best performance. More threads make things worse.
		if (autoConfigurationClasses.length > 1 && Runtime.getRuntime().availableProcessors() > 1) {
			return resolveOutcomesThreaded(autoConfigurationClasses, autoConfigurationMetadata);
		}
		else {
			OutcomesResolver outcomesResolver = new StandardOutcomesResolver(autoConfigurationClasses, 0,
					autoConfigurationClasses.length, autoConfigurationMetadata, getBeanClassLoader());
			return outcomesResolver.resolveOutcomes();
		}
	}

	private ConditionOutcome[] resolveOutcomesThreaded(String[] autoConfigurationClasses,
			AutoConfigurationMetadata autoConfigurationMetadata) {
		// 分两半,开启两个线程进行匹配
		int split = autoConfigurationClasses.length / 2;
		OutcomesResolver firstHalfResolver = createOutcomesResolver(autoConfigurationClasses, 0, split,
				autoConfigurationMetadata);

		OutcomesResolver secondHalfResolver = new StandardOutcomesResolver(autoConfigurationClasses, split,
				autoConfigurationClasses.length, autoConfigurationMetadata, getBeanClassLoader());

		ConditionOutcome[] secondHalf = secondHalfResolver.resolveOutcomes();
		ConditionOutcome[] firstHalf = firstHalfResolver.resolveOutcomes();
		ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
		System.arraycopy(firstHalf, 0, outcomes, 0, firstHalf.length);
		System.arraycopy(secondHalf, 0, outcomes, split, secondHalf.length);
		return outcomes;
	}

	private OutcomesResolver createOutcomesResolver(String[] autoConfigurationClasses, int start, int end,
			AutoConfigurationMetadata autoConfigurationMetadata) {
		OutcomesResolver outcomesResolver = new StandardOutcomesResolver(autoConfigurationClasses, start, end,
				autoConfigurationMetadata, getBeanClassLoader());
		try {
			return new ThreadedOutcomesResolver(outcomesResolver);
		}
		catch (AccessControlException ex) {
			return outcomesResolver;
		}
	}

	@Override
	public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
		ClassLoader classLoader = context.getClassLoader();
		ConditionMessage matchMessage = ConditionMessage.empty();

		// 拿到ConditionalOnClass注解中的value值,也就是要判断是否存在的类名
		List<String> onClasses = getCandidates(metadata, ConditionalOnClass.class);
		if (onClasses != null) {
			// 判断onClasses中不存在的类
			List<String> missing = filter(onClasses, ClassNameFilter.MISSING, classLoader);
			// 如果有缺失的类,那就表示不匹配
			if (!missing.isEmpty()) {
				return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)
						.didNotFind("required class", "required classes").items(Style.QUOTE, missing));
			}
			// 否则就表示匹配
			matchMessage = matchMessage.andCondition(ConditionalOnClass.class)
					.found("required class", "required classes")
					.items(Style.QUOTE, filter(onClasses, ClassNameFilter.PRESENT, classLoader));
		}

		// 和上面类似,只不过是判断onMissingClasses是不是全部缺失,如果是则表示匹配
		List<String> onMissingClasses = getCandidates(metadata, ConditionalOnMissingClass.class);
		if (onMissingClasses != null) {
			List<String> present = filter(onMissingClasses, ClassNameFilter.PRESENT, classLoader);
			if (!present.isEmpty()) {
				return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnMissingClass.class)
						.found("unwanted class", "unwanted classes").items(Style.QUOTE, present));
			}
			matchMessage = matchMessage.andCondition(ConditionalOnMissingClass.class)
					.didNotFind("unwanted class", "unwanted classes")
					.items(Style.QUOTE, filter(onMissingClasses, ClassNameFilter.MISSING, classLoader));
		}
		return ConditionOutcome.match(matchMessage);
	}

	private List<String> getCandidates(AnnotatedTypeMetadata metadata, Class<?> annotationType) {
		MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(annotationType.getName(), true);
		if (attributes == null) {
			return null;
		}
		List<String> candidates = new ArrayList<>();
		addAll(candidates, attributes.get("value"));
		addAll(candidates, attributes.get("name"));
		return candidates;
	}

	private void addAll(List<String> list, List<Object> itemsToAdd) {
		if (itemsToAdd != null) {
			for (Object item : itemsToAdd) {
				Collections.addAll(list, (String[]) item);
			}
		}
	}

	private interface OutcomesResolver {

		ConditionOutcome[] resolveOutcomes();

	}

	private static final class ThreadedOutcomesResolver implements OutcomesResolver {

		private final Thread thread;

		private volatile ConditionOutcome[] outcomes;

		private ThreadedOutcomesResolver(OutcomesResolver outcomesResolver) {
			this.thread = new Thread(() -> this.outcomes = outcomesResolver.resolveOutcomes());
			this.thread.start();
		}

		@Override
		public ConditionOutcome[] resolveOutcomes() {
			try {
				this.thread.join();
			}
			catch (InterruptedException ex) {
				Thread.currentThread().interrupt();
			}
			return this.outcomes;
		}

	}

	private static final class StandardOutcomesResolver implements OutcomesResolver {

		private final String[] autoConfigurationClasses;

		private final int start;

		private final int end;

		private final AutoConfigurationMetadata autoConfigurationMetadata;

		private final ClassLoader beanClassLoader;

		private StandardOutcomesResolver(String[] autoConfigurationClasses, int start, int end,
				AutoConfigurationMetadata autoConfigurationMetadata, ClassLoader beanClassLoader) {
			this.autoConfigurationClasses = autoConfigurationClasses;
			this.start = start;
			this.end = end;
			this.autoConfigurationMetadata = autoConfigurationMetadata;
			this.beanClassLoader = beanClassLoader;
		}

		@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];
				if (autoConfigurationClass != null) {
					// 从autoConfigurationMetadata中获取当前自动配置的ConditionalOnClass的属性,拿到的就是当前自动配置所需要的类
					String candidates = autoConfigurationMetadata.get(autoConfigurationClass, "ConditionalOnClass");
					if (candidates != null) {
						// 判断需要的类存不存在
						outcomes[i - start] = getOutcome(candidates);
					}
				}
			}
			return outcomes;
		}

		private ConditionOutcome getOutcome(String candidates) {
			try {
				if (!candidates.contains(",")) {
					return getOutcome(candidates, this.beanClassLoader);
				}
				for (String candidate : StringUtils.commaDelimitedListToStringArray(candidates)) {
					ConditionOutcome outcome = getOutcome(candidate, this.beanClassLoader);
					if (outcome != null) {
						return outcome;
					}
				}
			}
			catch (Exception ex) {
				// We'll get another chance later
			}
			return null;
		}

		private ConditionOutcome getOutcome(String className, ClassLoader classLoader) {
			if (ClassNameFilter.MISSING.matches(className, classLoader)) {
				return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)
						.didNotFind("required class").items(Style.QUOTE, className));
			}
			return null;
		}

	}

}

主要匹配的方法是 getMatchOutcome()

  1. 拿到使用 ConditionalOnClass 的所有类,存入 onClasses 集合;
  2. onClasses 集合不为空情况下,找到 onClasses 中不存在的类集合 missing,missing有记录表示不匹配,否则表示匹配;
  3. 查找使用 ConditionalOnMissingClass 的所有类,存入 onMissingClasses 集合;
  4. onMissingClasses集合不为空,找到 onMissingClasses 中存在的类集合 present,present有记录则表示不匹配,否则表示匹配。

3 ConditionalOnBean

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnBean {

	/**
	 * The class types of beans that should be checked. The condition matches when beans
	 * of all classes specified are contained in the {@link BeanFactory}.
	 * @return the class types of beans to check
	 */
	Class<?>[] value() default {};

	/**
	 * The class type names of beans that should be checked. The condition matches when
	 * beans of all classes specified are contained in the {@link BeanFactory}.
	 * @return the class type names of beans to check
	 */
	String[] type() default {};

	/**
	 * The annotation type decorating a bean that should be checked. The condition matches
	 * when all of the annotations specified are defined on beans in the
	 * {@link BeanFactory}.
	 * @return the class-level annotation types to check
	 */
	Class<? extends Annotation>[] annotation() default {};

	/**
	 * The names of beans to check. The condition matches when all of the bean names
	 * specified are contained in the {@link BeanFactory}.
	 * @return the names of beans to check
	 */
	String[] name() default {};

	/**
	 * Strategy to decide if the application context hierarchy (parent contexts) should be
	 * considered.
	 * @return the search strategy
	 */
	SearchStrategy search() default SearchStrategy.ALL;

	/**
	 * Additional classes that may contain the specified bean types within their generic
	 * parameters. For example, an annotation declaring {@code value=Name.class} and
	 * {@code parameterizedContainer=NameRegistration.class} would detect both
	 * {@code Name} and {@code NameRegistration}.
	 * @return the container types
	 * @since 2.1.0
	 */
	Class<?>[] parameterizedContainer() default {};

}

主要作用注解 @Conditional(OnBeanCondition.class) ,使用了 OnClassCondition 类,接下来我们看这个类做了什么。

@Order(Ordered.LOWEST_PRECEDENCE)
class OnBeanCondition extends FilteringSpringBootCondition implements ConfigurationCondition {

	@Override
	public ConfigurationPhase getConfigurationPhase() {
		return ConfigurationPhase.REGISTER_BEAN;
	}

	@Override
	protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
			AutoConfigurationMetadata autoConfigurationMetadata) {
		ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];

		// 遍历处理每个自动配置类
		for (int i = 0; i < outcomes.length; i++) {
			String autoConfigurationClass = autoConfigurationClasses[i];
			if (autoConfigurationClass != null) {

				// 当前自动配置中@ConditionalOnBean所依赖的类
				Set<String> onBeanTypes = autoConfigurationMetadata.getSet(autoConfigurationClass, "ConditionalOnBean");

				// 如果onBeanTypes都存在,则返回null
				outcomes[i] = getOutcome(onBeanTypes, ConditionalOnBean.class);

				if (outcomes[i] == null) {

					// 继续判断@ConditionalOnSingleCandidate所依赖的类
					Set<String> onSingleCandidateTypes = autoConfigurationMetadata.getSet(autoConfigurationClass,
							"ConditionalOnSingleCandidate");
					outcomes[i] = getOutcome(onSingleCandidateTypes, ConditionalOnSingleCandidate.class);
				}
			}
		}
		return outcomes;
	}

	private ConditionOutcome getOutcome(Set<String> requiredBeanTypes, Class<? extends Annotation> annotation) {
		List<String> missing = filter(requiredBeanTypes, ClassNameFilter.MISSING, getBeanClassLoader());

		// 有缺失的,则不会null
		if (!missing.isEmpty()) {
			ConditionMessage message = ConditionMessage.forCondition(annotation)
					.didNotFind("required type", "required types").items(Style.QUOTE, missing);
			return ConditionOutcome.noMatch(message);
		}

		// 没有缺失的,requiredBeanTypes类都存在则返回null
		return null;
	}

	@Override
	public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
		ConditionMessage matchMessage = ConditionMessage.empty();
		MergedAnnotations annotations = metadata.getAnnotations();

		// 如果存在ConditionalOnBean注解
		if (annotations.isPresent(ConditionalOnBean.class)) {
			Spec<ConditionalOnBean> spec = new Spec<>(context, metadata, annotations, ConditionalOnBean.class);
			MatchResult matchResult = getMatchingBeans(context, spec);

			// 如果某个Bean不存在
			if (!matchResult.isAllMatched()) {
				String reason = createOnBeanNoMatchReason(matchResult);
				return ConditionOutcome.noMatch(spec.message().because(reason));
			}

			// 所有Bean都存在
			matchMessage = spec.message(matchMessage).found("bean", "beans").items(Style.QUOTE,
					matchResult.getNamesOfAllMatches());
		}

		// 如果存在ConditionalOnSingleCandidate注解
		if (metadata.isAnnotated(ConditionalOnSingleCandidate.class.getName())) {
			Spec<ConditionalOnSingleCandidate> spec = new SingleCandidateSpec(context, metadata, annotations);
			MatchResult matchResult = getMatchingBeans(context, spec);

			// Bean不存在
			if (!matchResult.isAllMatched()) {
				return ConditionOutcome.noMatch(spec.message().didNotFind("any beans").atAll());
			}

			// Bean存在
			Set<String> allBeans = matchResult.getNamesOfAllMatches();

			// 如果只有一个
			if (allBeans.size() == 1) {
				matchMessage = spec.message(matchMessage).found("a single bean").items(Style.QUOTE, allBeans);
			}
			else {
				// 如果有多个
				List<String> primaryBeans = getPrimaryBeans(context.getBeanFactory(), allBeans,
						spec.getStrategy() == SearchStrategy.ALL);

				// 没有主Bean,那就不匹配
				if (primaryBeans.isEmpty()) {
					return ConditionOutcome.noMatch(
							spec.message().didNotFind("a primary bean from beans").items(Style.QUOTE, allBeans));
				}
				// 有多个主Bean,那就不匹配
				if (primaryBeans.size() > 1) {
					return ConditionOutcome
							.noMatch(spec.message().found("multiple primary beans").items(Style.QUOTE, primaryBeans));
				}

				// 只有一个主Bean
				matchMessage = spec.message(matchMessage)
						.found("a single primary bean '" + primaryBeans.get(0) + "' from beans")
						.items(Style.QUOTE, allBeans);
			}
		}

		// 存在ConditionalOnMissingBean注解
		if (metadata.isAnnotated(ConditionalOnMissingBean.class.getName())) {
			Spec<ConditionalOnMissingBean> spec = new Spec<>(context, metadata, annotations,
					ConditionalOnMissingBean.class);
			MatchResult matchResult = getMatchingBeans(context, spec);

			//有任意一个Bean存在,那就条件不匹配
			if (matchResult.isAnyMatched()) {
				String reason = createOnMissingBeanNoMatchReason(matchResult);
				return ConditionOutcome.noMatch(spec.message().because(reason));
			}

			// 都不存在在,则匹配
			matchMessage = spec.message(matchMessage).didNotFind("any beans").atAll();
		}
		return ConditionOutcome.match(matchMessage);
	}

	protected final MatchResult getMatchingBeans(ConditionContext context, Spec<?> spec) {
		ClassLoader classLoader = context.getClassLoader();

		// 获取BeanFactory
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		boolean considerHierarchy = spec.getStrategy() != SearchStrategy.CURRENT;
		Set<Class<?>> parameterizedContainers = spec.getParameterizedContainers();
		if (spec.getStrategy() == SearchStrategy.ANCESTORS) {
			BeanFactory parent = beanFactory.getParentBeanFactory();
			Assert.isInstanceOf(ConfigurableListableBeanFactory.class, parent,
					"Unable to use SearchStrategy.ANCESTORS");
			beanFactory = (ConfigurableListableBeanFactory) parent;
		}


		MatchResult result = new MatchResult();
		Set<String> beansIgnoredByType = getNamesOfBeansIgnoredByType(classLoader, beanFactory, considerHierarchy,
				spec.getIgnoredTypes(), parameterizedContainers);

		for (String type : spec.getTypes()) {
			// 获取指定类型的beanName
			Collection<String> typeMatches = getBeanNamesForType(classLoader, considerHierarchy, beanFactory, type,
					parameterizedContainers);

			// 如果beansIgnoredByType包含了当前类型,则把当前类型从typeMatches移除掉
			Iterator<String> iterator = typeMatches.iterator();
			while (iterator.hasNext()) {
				String match = iterator.next();
				if (beansIgnoredByType.contains(match) || ScopedProxyUtils.isScopedTarget(match)) {
					iterator.remove();
				}
			}

			// 该类型没有匹配的Bean
			if (typeMatches.isEmpty()) {
				result.recordUnmatchedType(type);
			}
			else {
				// 记录该类型所匹配的beanName结合
				result.recordMatchedType(type, typeMatches);
			}
		}
		for (String annotation : spec.getAnnotations()) {
			// 获取加了当前注解的beanNames
			Set<String> annotationMatches = getBeanNamesForAnnotation(classLoader, beanFactory, annotation,
					considerHierarchy);

			// 把beansIgnoredByType中的beanNames移除掉
			annotationMatches.removeAll(beansIgnoredByType);
			if (annotationMatches.isEmpty()) {
				result.recordUnmatchedAnnotation(annotation);
			}
			else {
				result.recordMatchedAnnotation(annotation, annotationMatches);
			}
		}

		for (String beanName : spec.getNames()) {
			// 当前beanName是否存在对应的bean
			if (!beansIgnoredByType.contains(beanName) && containsBean(beanFactory, beanName, considerHierarchy)) {
				result.recordMatchedName(beanName);
			}
			else {
				result.recordUnmatchedName(beanName);
			}
		}
		return result;
	}

	private Set<String> getNamesOfBeansIgnoredByType(ClassLoader classLoader, ListableBeanFactory beanFactory,
			boolean considerHierarchy, Set<String> ignoredTypes, Set<Class<?>> parameterizedContainers) {
		Set<String> result = null;
		for (String ignoredType : ignoredTypes) {
			Collection<String> ignoredNames = getBeanNamesForType(classLoader, considerHierarchy, beanFactory,
					ignoredType, parameterizedContainers);
			result = addAll(result, ignoredNames);
		}
		return (result != null) ? result : Collections.emptySet();
	}

	private Set<String> getBeanNamesForType(ClassLoader classLoader, boolean considerHierarchy,
			ListableBeanFactory beanFactory, String type, Set<Class<?>> parameterizedContainers) throws LinkageError {
		try {
			return getBeanNamesForType(beanFactory, considerHierarchy, resolve(type, classLoader),
					parameterizedContainers);
		}
		catch (ClassNotFoundException | NoClassDefFoundError ex) {
			return Collections.emptySet();
		}
	}

	private Set<String> getBeanNamesForType(ListableBeanFactory beanFactory, boolean considerHierarchy, Class<?> type,
			Set<Class<?>> parameterizedContainers) {
		Set<String> result = collectBeanNamesForType(beanFactory, considerHierarchy, type, parameterizedContainers,
				null);
		return (result != null) ? result : Collections.emptySet();
	}

	private Set<String> collectBeanNamesForType(ListableBeanFactory beanFactory, boolean considerHierarchy,
			Class<?> type, Set<Class<?>> parameterizedContainers, Set<String> result) {
		result = addAll(result, beanFactory.getBeanNamesForType(type, true, false));
		for (Class<?> container : parameterizedContainers) {
			ResolvableType generic = ResolvableType.forClassWithGenerics(container, type);
			result = addAll(result, beanFactory.getBeanNamesForType(generic, true, false));
		}
		if (considerHierarchy && beanFactory instanceof HierarchicalBeanFactory) {
			BeanFactory parent = ((HierarchicalBeanFactory) beanFactory).getParentBeanFactory();
			if (parent instanceof ListableBeanFactory) {
				result = collectBeanNamesForType((ListableBeanFactory) parent, considerHierarchy, type,
						parameterizedContainers, result);
			}
		}
		return result;
	}

	private Set<String> getBeanNamesForAnnotation(ClassLoader classLoader, ConfigurableListableBeanFactory beanFactory,
			String type, boolean considerHierarchy) throws LinkageError {
		Set<String> result = null;
		try {
			result = collectBeanNamesForAnnotation(beanFactory, resolveAnnotationType(classLoader, type),
					considerHierarchy, result);
		}
		catch (ClassNotFoundException ex) {
			// Continue
		}
		return (result != null) ? result : Collections.emptySet();
	}

	@SuppressWarnings("unchecked")
	private Class<? extends Annotation> resolveAnnotationType(ClassLoader classLoader, String type)
			throws ClassNotFoundException {
		return (Class<? extends Annotation>) resolve(type, classLoader);
	}

	private Set<String> collectBeanNamesForAnnotation(ListableBeanFactory beanFactory,
			Class<? extends Annotation> annotationType, boolean considerHierarchy, Set<String> result) {
		result = addAll(result, beanFactory.getBeanNamesForAnnotation(annotationType));
		if (considerHierarchy) {
			BeanFactory parent = ((HierarchicalBeanFactory) beanFactory).getParentBeanFactory();
			if (parent instanceof ListableBeanFactory) {
				result = collectBeanNamesForAnnotation((ListableBeanFactory) parent, annotationType, considerHierarchy,
						result);
			}
		}
		return result;
	}

	private boolean containsBean(ConfigurableListableBeanFactory beanFactory, String beanName,
			boolean considerHierarchy) {
		if (considerHierarchy) {
			return beanFactory.containsBean(beanName);
		}
		return beanFactory.containsLocalBean(beanName);
	}

	private String createOnBeanNoMatchReason(MatchResult matchResult) {
		StringBuilder reason = new StringBuilder();
		appendMessageForNoMatches(reason, matchResult.getUnmatchedAnnotations(), "annotated with");
		appendMessageForNoMatches(reason, matchResult.getUnmatchedTypes(), "of type");
		appendMessageForNoMatches(reason, matchResult.getUnmatchedNames(), "named");
		return reason.toString();
	}

	private void appendMessageForNoMatches(StringBuilder reason, Collection<String> unmatched, String description) {
		if (!unmatched.isEmpty()) {
			if (reason.length() > 0) {
				reason.append(" and ");
			}
			reason.append("did not find any beans ");
			reason.append(description);
			reason.append(" ");
			reason.append(StringUtils.collectionToDelimitedString(unmatched, ", "));
		}
	}

	private String createOnMissingBeanNoMatchReason(MatchResult matchResult) {
		StringBuilder reason = new StringBuilder();
		appendMessageForMatches(reason, matchResult.getMatchedAnnotations(), "annotated with");
		appendMessageForMatches(reason, matchResult.getMatchedTypes(), "of type");
		if (!matchResult.getMatchedNames().isEmpty()) {
			if (reason.length() > 0) {
				reason.append(" and ");
			}
			reason.append("found beans named ");
			reason.append(StringUtils.collectionToDelimitedString(matchResult.getMatchedNames(), ", "));
		}
		return reason.toString();
	}

	private void appendMessageForMatches(StringBuilder reason, Map<String, Collection<String>> matches,
			String description) {
		if (!matches.isEmpty()) {
			matches.forEach((key, value) -> {
				if (reason.length() > 0) {
					reason.append(" and ");
				}
				reason.append("found beans ");
				reason.append(description);
				reason.append(" '");
				reason.append(key);
				reason.append("' ");
				reason.append(StringUtils.collectionToDelimitedString(value, ", "));
			});
		}
	}

	private List<String> getPrimaryBeans(ConfigurableListableBeanFactory beanFactory, Set<String> beanNames,
			boolean considerHierarchy) {
		List<String> primaryBeans = new ArrayList<>();
		for (String beanName : beanNames) {
			BeanDefinition beanDefinition = findBeanDefinition(beanFactory, beanName, considerHierarchy);
			if (beanDefinition != null && beanDefinition.isPrimary()) {
				primaryBeans.add(beanName);
			}
		}
		return primaryBeans;
	}

	private BeanDefinition findBeanDefinition(ConfigurableListableBeanFactory beanFactory, String beanName,
			boolean considerHierarchy) {
		if (beanFactory.containsBeanDefinition(beanName)) {
			return beanFactory.getBeanDefinition(beanName);
		}
		if (considerHierarchy && beanFactory.getParentBeanFactory() instanceof ConfigurableListableBeanFactory) {
			return findBeanDefinition(((ConfigurableListableBeanFactory) beanFactory.getParentBeanFactory()), beanName,
					considerHierarchy);
		}
		return null;
	}

	private static Set<String> addAll(Set<String> result, Collection<String> additional) {
		if (CollectionUtils.isEmpty(additional)) {
			return result;
		}
		result = (result != null) ? result : new LinkedHashSet<>();
		result.addAll(additional);
		return result;
	}

	private static Set<String> addAll(Set<String> result, String[] additional) {
		if (ObjectUtils.isEmpty(additional)) {
			return result;
		}
		result = (result != null) ? result : new LinkedHashSet<>();
		Collections.addAll(result, additional);
		return result;
	}

	/**
	 * A search specification extracted from the underlying annotation.
	 */
	private static class Spec<A extends Annotation> {

		private final ClassLoader classLoader;

		private final Class<? extends Annotation> annotationType;

		private final Set<String> names;

		private final Set<String> types;

		private final Set<String> annotations;

		private final Set<String> ignoredTypes;

		private final Set<Class<?>> parameterizedContainers;

		private final SearchStrategy strategy;

		Spec(ConditionContext context, AnnotatedTypeMetadata metadata, MergedAnnotations annotations,
				Class<A> annotationType) {
			MultiValueMap<String, Object> attributes = annotations.stream(annotationType)
					.filter(MergedAnnotationPredicates.unique(MergedAnnotation::getMetaTypes))
					.collect(MergedAnnotationCollectors.toMultiValueMap(Adapt.CLASS_TO_STRING));
			MergedAnnotation<A> annotation = annotations.get(annotationType);
			this.classLoader = context.getClassLoader();
			this.annotationType = annotationType;
			this.names = extract(attributes, "name");
			this.annotations = extract(attributes, "annotation");
			this.ignoredTypes = extract(attributes, "ignored", "ignoredType");
			this.parameterizedContainers = resolveWhenPossible(extract(attributes, "parameterizedContainer"));
			this.strategy = annotation.getValue("search", SearchStrategy.class).orElse(null);
			Set<String> types = extractTypes(attributes);
			BeanTypeDeductionException deductionException = null;
			if (types.isEmpty() && this.names.isEmpty()) {
				try {
					types = deducedBeanType(context, metadata);
				}
				catch (BeanTypeDeductionException ex) {
					deductionException = ex;
				}
			}
			this.types = types;
			validate(deductionException);
		}

		protected Set<String> extractTypes(MultiValueMap<String, Object> attributes) {
			return extract(attributes, "value", "type");
		}

		private Set<String> extract(MultiValueMap<String, Object> attributes, String... attributeNames) {
			if (attributes.isEmpty()) {
				return Collections.emptySet();
			}
			Set<String> result = new LinkedHashSet<>();
			for (String attributeName : attributeNames) {
				List<Object> values = attributes.getOrDefault(attributeName, Collections.emptyList());
				for (Object value : values) {
					if (value instanceof String[]) {
						merge(result, (String[]) value);
					}
					else if (value instanceof String) {
						merge(result, (String) value);
					}
				}
			}
			return result.isEmpty() ? Collections.emptySet() : result;
		}

		private void merge(Set<String> result, String... additional) {
			Collections.addAll(result, additional);
		}

		private Set<Class<?>> resolveWhenPossible(Set<String> classNames) {
			if (classNames.isEmpty()) {
				return Collections.emptySet();
			}
			Set<Class<?>> resolved = new LinkedHashSet<>(classNames.size());
			for (String className : classNames) {
				try {
					resolved.add(resolve(className, this.classLoader));
				}
				catch (ClassNotFoundException | NoClassDefFoundError ex) {
				}
			}
			return resolved;
		}

		protected void validate(BeanTypeDeductionException ex) {
			if (!hasAtLeastOneElement(this.types, this.names, this.annotations)) {
				String message = getAnnotationName() + " did not specify a bean using type, name or annotation";
				if (ex == null) {
					throw new IllegalStateException(message);
				}
				throw new IllegalStateException(message + " and the attempt to deduce the bean's type failed", ex);
			}
		}

		private boolean hasAtLeastOneElement(Set<?>... sets) {
			for (Set<?> set : sets) {
				if (!set.isEmpty()) {
					return true;
				}
			}
			return false;
		}

		protected final String getAnnotationName() {
			return "@" + ClassUtils.getShortName(this.annotationType);
		}

		private Set<String> deducedBeanType(ConditionContext context, AnnotatedTypeMetadata metadata) {
			if (metadata instanceof MethodMetadata && metadata.isAnnotated(Bean.class.getName())) {
				return deducedBeanTypeForBeanMethod(context, (MethodMetadata) metadata);
			}
			return Collections.emptySet();
		}

		private Set<String> deducedBeanTypeForBeanMethod(ConditionContext context, MethodMetadata metadata) {
			try {
				Class<?> returnType = getReturnType(context, metadata);
				return Collections.singleton(returnType.getName());
			}
			catch (Throwable ex) {
				throw new BeanTypeDeductionException(metadata.getDeclaringClassName(), metadata.getMethodName(), ex);
			}
		}

		private Class<?> getReturnType(ConditionContext context, MethodMetadata metadata)
				throws ClassNotFoundException, LinkageError {
			// Safe to load at this point since we are in the REGISTER_BEAN phase
			ClassLoader classLoader = context.getClassLoader();
			Class<?> returnType = resolve(metadata.getReturnTypeName(), classLoader);
			if (isParameterizedContainer(returnType)) {
				returnType = getReturnTypeGeneric(metadata, classLoader);
			}
			return returnType;
		}

		private boolean isParameterizedContainer(Class<?> type) {
			for (Class<?> parameterizedContainer : this.parameterizedContainers) {
				if (parameterizedContainer.isAssignableFrom(type)) {
					return true;
				}
			}
			return false;
		}

		private Class<?> getReturnTypeGeneric(MethodMetadata metadata, ClassLoader classLoader)
				throws ClassNotFoundException, LinkageError {
			Class<?> declaringClass = resolve(metadata.getDeclaringClassName(), classLoader);
			Method beanMethod = findBeanMethod(declaringClass, metadata.getMethodName());
			return ResolvableType.forMethodReturnType(beanMethod).resolveGeneric();
		}

		private Method findBeanMethod(Class<?> declaringClass, String methodName) {
			Method method = ReflectionUtils.findMethod(declaringClass, methodName);
			if (isBeanMethod(method)) {
				return method;
			}
			Method[] candidates = ReflectionUtils.getAllDeclaredMethods(declaringClass);
			for (Method candidate : candidates) {
				if (candidate.getName().equals(methodName) && isBeanMethod(candidate)) {
					return candidate;
				}
			}
			throw new IllegalStateException("Unable to find bean method " + methodName);
		}

		private boolean isBeanMethod(Method method) {
			return method != null && MergedAnnotations.from(method, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY)
					.isPresent(Bean.class);
		}

		private SearchStrategy getStrategy() {
			return (this.strategy != null) ? this.strategy : SearchStrategy.ALL;
		}

		Set<String> getNames() {
			return this.names;
		}

		Set<String> getTypes() {
			return this.types;
		}

		Set<String> getAnnotations() {
			return this.annotations;
		}

		Set<String> getIgnoredTypes() {
			return this.ignoredTypes;
		}

		Set<Class<?>> getParameterizedContainers() {
			return this.parameterizedContainers;
		}

		ConditionMessage.Builder message() {
			return ConditionMessage.forCondition(this.annotationType, this);
		}

		ConditionMessage.Builder message(ConditionMessage message) {
			return message.andCondition(this.annotationType, this);
		}

		@Override
		public String toString() {
			boolean hasNames = !this.names.isEmpty();
			boolean hasTypes = !this.types.isEmpty();
			boolean hasIgnoredTypes = !this.ignoredTypes.isEmpty();
			StringBuilder string = new StringBuilder();
			string.append("(");
			if (hasNames) {
				string.append("names: ");
				string.append(StringUtils.collectionToCommaDelimitedString(this.names));
				string.append(hasTypes ? " " : "; ");
			}
			if (hasTypes) {
				string.append("types: ");
				string.append(StringUtils.collectionToCommaDelimitedString(this.types));
				string.append(hasIgnoredTypes ? " " : "; ");
			}
			if (hasIgnoredTypes) {
				string.append("ignored: ");
				string.append(StringUtils.collectionToCommaDelimitedString(this.ignoredTypes));
				string.append("; ");
			}
			string.append("SearchStrategy: ");
			string.append(this.strategy.toString().toLowerCase(Locale.ENGLISH));
			string.append(")");
			return string.toString();
		}

	}

	/**
	 * Specialized {@link Spec specification} for
	 * {@link ConditionalOnSingleCandidate @ConditionalOnSingleCandidate}.
	 */
	private static class SingleCandidateSpec extends Spec<ConditionalOnSingleCandidate> {

		private static final Collection<String> FILTERED_TYPES = Arrays.asList("", Object.class.getName());

		SingleCandidateSpec(ConditionContext context, AnnotatedTypeMetadata metadata, MergedAnnotations annotations) {
			super(context, metadata, annotations, ConditionalOnSingleCandidate.class);
		}

		@Override
		protected Set<String> extractTypes(MultiValueMap<String, Object> attributes) {
			Set<String> types = super.extractTypes(attributes);
			types.removeAll(FILTERED_TYPES);
			return types;
		}

		@Override
		protected void validate(BeanTypeDeductionException ex) {
			Assert.isTrue(getTypes().size() == 1,
					() -> getAnnotationName() + " annotations must specify only one type (got "
							+ StringUtils.collectionToCommaDelimitedString(getTypes()) + ")");
		}

	}

	/**
	 * Results collected during the condition evaluation.
	 */
	private static final class MatchResult {

		private final Map<String, Collection<String>> matchedAnnotations = new HashMap<>();

		private final List<String> matchedNames = new ArrayList<>();

		private final Map<String, Collection<String>> matchedTypes = new HashMap<>();

		private final List<String> unmatchedAnnotations = new ArrayList<>();

		private final List<String> unmatchedNames = new ArrayList<>();

		private final List<String> unmatchedTypes = new ArrayList<>();

		private final Set<String> namesOfAllMatches = new HashSet<>();

		private void recordMatchedName(String name) {
			this.matchedNames.add(name);
			this.namesOfAllMatches.add(name);
		}

		private void recordUnmatchedName(String name) {
			this.unmatchedNames.add(name);
		}

		private void recordMatchedAnnotation(String annotation, Collection<String> matchingNames) {
			this.matchedAnnotations.put(annotation, matchingNames);
			this.namesOfAllMatches.addAll(matchingNames);
		}

		private void recordUnmatchedAnnotation(String annotation) {
			this.unmatchedAnnotations.add(annotation);
		}

		private void recordMatchedType(String type, Collection<String> matchingNames) {
			this.matchedTypes.put(type, matchingNames);
			this.namesOfAllMatches.addAll(matchingNames);
		}

		private void recordUnmatchedType(String type) {
			this.unmatchedTypes.add(type);
		}

		boolean isAllMatched() {
			return this.unmatchedAnnotations.isEmpty() && this.unmatchedNames.isEmpty()
					&& this.unmatchedTypes.isEmpty();
		}

		boolean isAnyMatched() {
			return (!this.matchedAnnotations.isEmpty()) || (!this.matchedNames.isEmpty())
					|| (!this.matchedTypes.isEmpty());
		}

		Map<String, Collection<String>> getMatchedAnnotations() {
			return this.matchedAnnotations;
		}

		List<String> getMatchedNames() {
			return this.matchedNames;
		}

		Map<String, Collection<String>> getMatchedTypes() {
			return this.matchedTypes;
		}

		List<String> getUnmatchedAnnotations() {
			return this.unmatchedAnnotations;
		}

		List<String> getUnmatchedNames() {
			return this.unmatchedNames;
		}

		List<String> getUnmatchedTypes() {
			return this.unmatchedTypes;
		}

		Set<String> getNamesOfAllMatches() {
			return this.namesOfAllMatches;
		}

	}

	/**
	 * Exception thrown when the bean type cannot be deduced.
	 */
	static final class BeanTypeDeductionException extends RuntimeException {

		private BeanTypeDeductionException(String className, String beanMethodName, Throwable cause) {
			super("Failed to deduce bean type for " + className + "." + beanMethodName, cause);
		}

	}

}

此条件注解解析含 ConditionalOnBean 的类,逻辑和 OnClassCondition 类似。

四、Starter机制

Starter就是一个Maven依赖,当我们在项目的pom.xml文件中添加某个Starter
依赖时,其实就是简单的添加了很多其他的依赖,比如:

  1. spring-boot-starter-web:引入了spring-boot-starter、spring-boot-starter-json、spring-boot-starter-tomcat等和
    Web开发相关的依赖包。
  2. spring-boot-starter-tomcat:引入了tomcat-embed-core、tomcat-embed-el、tomcat-embed-websocket等和
    Tomcat相关的依赖包。
<dependency>
	 <groupId>org.springframework.boot</groupId>
	 <artifactId>spring-boot-starter-web</artifactId>
</dependency>

引入此starter的pom包,Springboot会使用条件注解自动将tomcat的依赖加到项目中。

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnMissingBean(ReactiveWebServerFactory.class)
	@ConditionalOnClass({ org.apache.catalina.startup.Tomcat.class })
	static class EmbeddedTomcat {

		@Bean
		TomcatReactiveWebServerFactory tomcatReactiveWebServerFactory(
				ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
				ObjectProvider<TomcatContextCustomizer> contextCustomizers,
				ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
			TomcatReactiveWebServerFactory factory = new TomcatReactiveWebServerFactory();
			factory.getTomcatConnectorCustomizers()
					.addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));
			factory.getTomcatContextCustomizers()
					.addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));
			factory.getTomcatProtocolHandlerCustomizers()
					.addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));
			return factory;
		}

	}

通过 @ConditionalOnClass 条件注解,发现 org.apache.catalina.startup.Tomcat.class 类存在,则引入 EmbeddedTomcat 类。

五、自动配置开启原理

@SpringBootApplication
public class MyApplication {

	public static void main(String[] args) {
		SpringApplication.run(MyApplication.class, args);
	}

}

Springboot项目中通常使用 SpringBootApplication 注解,此注解是合成注解,里面包含启动所需的配置类。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
// AutoConfigurationExcludeFilter的作用是扫描到的配置类名字如果在自动配置类名集合中,就不解析
public @interface SpringBootApplication {
	...
}

可以发现这个注解上有另外三个注解:

  1. @SpringBootConfiguration
  2. @EnableAutoConfiguration
  3. @ComponentScan
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
	...
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

	/**
	 * Environment property that can be used to override when auto-configuration is
	 * enabled.
	 */
	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	/**
	 * Exclude specific auto-configuration classes such that they will never be applied.
	 * @return the classes to exclude
	 */
	Class<?>[] exclude() default {};

	/**
	 * Exclude specific auto-configuration class names such that they will never be
	 * applied.
	 * @return the class names to exclude
	 * @since 1.3.0
	 */
	String[] excludeName() default {};

}

EnableAutoConfiguration 核心是@Import(AutoConfigurationImportSelector.class),而AutoConfigurationImportSelector实现了DeferredImportSelector这个接口,Spring容器在启动时,会在解析完其他所有程序员定义的配置类之后,来调用AutoConfigurationImportSelector中的selectImports方法,然后把该方法返回的类名对应的类作为配置类进行解析。

该方法会利用SpringFactoriesLoader找到所有的META-INF/spring.factories文件中key为
EnableAutoConfiguration.class的value值,也就是众多自动配置类的类名。

拿到这些类名后会进行去重,去重的代码为:

new ArrayList<>(new LinkedHashSet<>(list))

去重完之后,就会看是否存在某些自动配置类需要排除,我们可以通过@EnableAutoConfiguration
注解的exclude属性,或者spring.autoconfigure.exclude配置来指定一些自动配置类的名字,然后把
它们从自动配置类集合中排除掉。

然后会继续利用ConfigurationClassFilter对自动配置类进行进一步筛选,ConfigurationClassFilter会利用AutoConfigurationMetadata进行筛选,而AutoConfigurationMetadata对象对应的是"METAINF/spring-autoconfigure-metadata.properties"文件中的内容,这是一种加快SpringBoot启动速度的机制,默认是开启了的(不过要通过maven或gradle的方式引入springboot的依赖来使用才能看到效果,因为这个文件的内容是在SpringBoot源码工程编译的时候自动生成出来的。

此配置文件可手动创建:自动配置类名.条件注解=条件

有了这个文件的内容,SpringBoot会在通过spring.facotries文件找到所有的自动配置类后,会把这个
文件中的内容读出来,然后利用AutoConfigurationImportFilter对所有的自动配置类进行条件匹配,
这里的条件判断,只会判断所需要的类是否存在,如果需要的类,或者需要的Bean对应的类,都不存
在,那么肯定不符合条件了,对于像@ConditionalOnMissingBean这样的条件,在这一步是不会去
判断的,最后条件匹配成功的自动配置类就会记录下来,并最终返回给Spring容器,继续进行其他条
件的匹配。
所以通过这个机制,使得Spring并不需要解析所有的自动配置类,从而提高了效率。

六、Spring Boot整合Tomcat底层原理

项目添加的starter为:spring-boot-starter-web,那么我们启动项目时,SpringBoot就会自动启动一个Tomcat。

在spring-boot-starter-web这个starter中,其实简介的引入了spring-bootstarter-tomcat这个starter,这个spring-boot-starter-tomcat又引入了tomcat-embed-core依赖,所以只要我们项目中依赖了spring-boot-starter-web就相当于依赖了Tomcat。

@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
		ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
		ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
		ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
	...
}

这个自动配置类所需要的条件:

  1. @ConditionalOnClass(ServletRequest.class):表示项目依赖中要有ServletRequest类(server api)
  2. @ConditionalOnWebApplication(type = Type.SERVLET):表示项目应用类型得是SpringMVC(讲启动过程的时
    候就知道如何判断一个SpringBoot应用的类型了)

在上面提到的spring-boot-starter-web中,其实还间接的引入了spring-web、spring-webmvc等依赖,这就使得第二个条件满足,而对于第一个条件的ServletRequest类,虽然它是Servlet规范中的类,但是在我们所依赖的tomcat-embed-core这个jar包中是存在这个类的,这是因为Tomcat在自己的源码中把Servlet规范中的一些代码也包含进去了,比如:
Springboot自动装配以及启动原理解析_第1张图片
这就使得ServletWebServerFactoryAutoConfiguration这个自动配置的两个条件都符合,那么Spring就能去解析它,一解析它就发现这个自动配置类Import进来了三个类:

  1. ServletWebServerFactoryConfiguration.EmbeddedTomcat.class
  2. ServletWebServerFactoryConfiguration.EmbeddedJetty.class
  3. ServletWebServerFactoryConfiguration.EmbeddedUndertow.class

Import进来的这三个类应该是差不多,我们看EmbeddedTomcat这个类:

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
	@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
	static class EmbeddedTomcat {

		...

	}

可以发现这个类是一个配置类,所以Spring也会来解析它,不过它也有两个条件:

  1. @ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class }):项目依赖中要有Servlet.class、 Tomcat.class、UpgradeProtocol.class这三个类,这个条件比较容易理解,项目依赖中有Tomcat的类,那这个条件就符合。
  2. @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT),项目中没有ServletWebServerFactory类型的Bean,因为这个配置类的内部就是定义了一个
    TomcatServletWebServerFactory类型的Bean,TomcatServletWebServerFactory实现了
    ServletWebServerFactory接口,所以这个条件注解的意思就是,如果程序员自己没有定义
    ServletWebServerFactory类型的Bean,那么就符合条件,不然,如果程序员自己定义了
    ServletWebServerFactory类型的Bean,那么条件就不符合,也就导致SpringBoot给我们定义的
    TomcatServletWebServerFactory这个Bean就不会生效,最终生效的就是程序员自己定义的。

所以,通常只要我们项目依赖中有Tomcat依赖,那就符合条件,那最终Spring容器中就会有
TomcatServletWebServerFactory这个Bean。

对于另外的EmbeddedJetty和EmbeddedUndertow,也差不多,都是判断项目依赖中是否有Jetty和Undertow的依赖,如果有,那么对应在Spring容器中就会存在JettyServletWebServerFactory类型的Bean、或者存在UndertowServletWebServerFactory类型的Bean。

总结一下:

  1. 有Tomcat依赖,就有TomcatServletWebServerFactory这个Bean
  2. 有Jetty依赖,就有JettyServletWebServerFactory这个Bean
  3. 有Undertow依赖,就有UndertowServletWebServerFactory这个Bean

ServletWebServerFactory其实就是用来获得WebServer对象的,而WebServer拥有启动、停止、获取端口等方法,那么很自然,我们就发现WebServer其实指的就是Tomcat、Jetty、Undertow,而TomcatServletWebServerFactory就是用来生成Tomcat所对应的WebServer对象,具体一点就是TomcatWebServer对象,并且在生成TomcatWebServer对象时会把Tomcat给启动起来,在源码中,调用TomcatServletWebServerFactory对象的getWebServer()方法时就会启动Tomcat。

再看TomcatServletWebServerFactory这个Bean的定义:

	@Bean
	TomcatServletWebServerFactory tomcatServletWebServerFactory(
			ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
			ObjectProvider<TomcatContextCustomizer> contextCustomizers,
			ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
		TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();

		// orderedStream()调用时会去Spring容器中找到TomcatConnectorCustomizer类型的Bean,默认是没有的,程序员可以自己定义
		factory.getTomcatConnectorCustomizers()
				.addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));
		factory.getTomcatContextCustomizers()
				.addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));
		factory.getTomcatProtocolHandlerCustomizers()
				.addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));
		return factory;
	}

要构造这个Bean,Spring会从Spring容器中获取到TomcatConnectorCustomizer、TomcatContextCustomizer、TomcatProtocolHandlerCustomizer这三个类型的Bean,然后把它们添加到TomcatServletWebServerFactory对象中去,很明显这三种Bean是用来配置Tomcat的,比如:

  1. TomcatConnectorCustomizer:是用来配置Tomcat中的Connector组件的
  2. TomcatContextCustomizer:是用来配置Tomcat中的Context组件的
  3. TomcatProtocolHandlerCustomizer:是用来配置Tomcat中的ProtocolHandler组件的

也就是我们可以通过定义TomcatConnectorCustomizer类型的Bean,来对Tomcat进行配置,比如:

@SpringBootApplication
public class MyApplication {

@Bean
public TomcatConnectorCustomizer tomcatConnectorCustomizer(){
	return new TomcatConnectorCustomizer() {
		@Override
		public void customize(Connector connector) {
		connector.setPort(8888);
		}

/*
这样Tomcat就会绑定8888这个端口。有了TomcatServletWebServerFactory这个Bean之后,在SpringBoot的启动过程中,会执行ServletWebServerApplicationContext的onRefresh()方法,而这个方法会调用createWebServer()方法,而这个方法中最为重要的两行代码为:
很明显,getWebServerFactory()负责获取具体的ServletWebServerFactory对象,要么是
TomcatServletWebServerFactory对象,要么是JettyServletWebServerFactory对象,要么是
UndertowServletWebServerFactory对象,注意只能获取到一个,然后调用该对象的getWebServer
方法,启动对应的Tomcat、或者Jetty、或者Undertow。
getWebServerFactory方法中的逻辑比较简单,获取Spring容器中的ServletWebServerFactory类型
的Bean对象,如果没有获取到则抛异常,如果找到多个也抛异常,也就是在Spring容器中只能有一个
ServletWebServerFactory类型的Bean对象。
拿到TomcatServletWebServerFactory对象后,就调用它的getWebServer方法,而在这个方法中就
会生成一个Tomcat对象,并且利用前面的TomcatConnectorCustomizer等等会Tomcat对象进行配
置,最后启动Tomcat。
这样在启动应用时就完成了Tomcat的启动,到此我们通过这个案例也看到了具体的Starter机制、自动
配置的具体使用。
不过额外有一点要提一下,我们前面提到了我们可以利用TomcatConnectorCustomizer对Tomca中
的Connector组件进行配置,我们可能会想到默认情况下,SpringBoot是不是就是提供了一个
*/
		};
	}

	public static void main(String[] args) {
		SpringApplication.run(MyApplication.class);
	}
}

这样Tomcat就会绑定8888这个端口。

有了TomcatServletWebServerFactory这个Bean之后,在SpringBoot的启动过程中,会执行ServletWebServerApplicationContext的onRefresh()方法,而这个方法会调用createWebServer()方法,而这个方法中最为重要的两行代码为:

 ServletWebServerFactory factory = getWebServerFactory();
 this.webServer = factory.getWebServer(getSelfInitializer());

getWebServerFactory()负责获取具体的ServletWebServerFactory对象,要么是TomcatServletWebServerFactory对象,要么是JettyServletWebServerFactory对象,要么是UndertowServletWebServerFactory对象,注意只能获取到一个,然后调用该对象的getWebServer方法,启动对应的Tomcat、或者Jetty、或者Undertow。

getWebServerFactory方法中的逻辑比较简单,获取Spring容器中的ServletWebServerFactory类型的Bean对象,如果没有获取到则抛异常,如果找到多个也抛异常,也就是在Spring容器中只能有一个ServletWebServerFactory类型的Bean对象。

拿到TomcatServletWebServerFactory对象后,就调用它的getWebServer方法,而在这个方法中就会生成一个Tomcat对象,并且利用前面的TomcatConnectorCustomizer等等会Tomcat对象进行配置,最后启动Tomcat。

这样在启动应用时就完成了Tomcat的启动,到此我们通过这个案例也看到了具体的Starter机制、自动
配置的具体使用。

在自动配置类ServletWebServerFactoryAutoConfiguration中,会定义一个ServletWebServerFactoryCustomizer类型的Bean:

	@Bean
	public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties,
			ObjectProvider<WebListenerRegistrar> webListenerRegistrars,
			ObjectProvider<CookieSameSiteSupplier> cookieSameSiteSuppliers) {
		return new ServletWebServerFactoryCustomizer(serverProperties,
				webListenerRegistrars.orderedStream().collect(Collectors.toList()),
				cookieSameSiteSuppliers.orderedStream().collect(Collectors.toList()));
	}

这个Bean会接收一个ServerProperties的Bean,ServerProperties的Bean对应的就是properties文
件中前缀为server的配置,我们可以利用ServerProperties对象的getPort方法获取到我们所配置的
server.port的值。

而ServletWebServerFactoryCustomizer是针对一个ServletWebServerFactory的自定义器,也就是用来配TomcatServletWebServerFactory这个Bean的,到时候ServletWebServerFactoryCustomizer就会利用ServerProperties对象来对TomcatServletWebServerFactory对象进行设置。

在ServletWebServerFactoryAutoConfiguration这个自动配置上,除开Import了EmbeddedTomcat、EmbeddedJetty、EmbeddedUndertow这三个配置类,还Import了一个ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,这个BeanPostProcessorsRegistrar会向Spring容器中注册一个WebServerFactoryCustomizerBeanPostProcessor类型的Bean。

WebServerFactoryCustomizerBeanPostProcessor是一个BeanPosrtProcessor,它专门用来处理类型为WebServerFactory的Bean对象,而我们的TomcatServletWebServerFactory、JettyServletWebServerFactory、UndertowServletWebServerFactory也都实现了这个接口,所以
不管当前项目依赖的情况,只要在Spring在创建比如TomcatServletWebServerFactory这个Bean时WebServerFactoryCustomizerBeanPostProcessor就会对它进行处理,处理的逻辑为:

  1. 从Spring容器中拿到WebServerFactoryCustomizer类型的Bean,也就是前面说的
    ServletWebServerFactoryCustomizer对象
  2. 然后调用ServletWebServerFactoryCustomizer对象的customize方法,把TomcatServletWebServerFactory对象
    传入进去
  3. customize方法中就会从ServerProperties对象获取各种配置,然后设置给TomcatServletWebServerFactory对象

总结,SpringBoot整合Tomcat的核心原理主要涉及的东西有:

  1. spring-boot-starter-web:会自动引入Tomcat、SpringMVC的依赖
  2. ServletWebServerFactoryAutoConfiguration:自动配置类
  3. ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar:用来注册
    WebServerFactoryCustomizerBeanPostProcessor
  4. ServletWebServerFactoryConfiguration.EmbeddedTomcat:配置TomcatServletWebServerFactory
  5. ServletWebServerFactoryConfiguration.EmbeddedJetty:配置JettyServletWebServerFactory
  6. ServletWebServerFactoryConfiguration.EmbeddedUndertow:配置UndertowServletWebServerFactory
  7. ServletWebServerFactoryCustomizer:用来配置ServletWebServerFactory
  8. WebServerFactoryCustomizerBeanPostProcessor:是一个BeanPostProcessor,利用ServletWebServerFactoryCustomizer来配置ServletWebServerFactory
  9. ServletWebServerApplicationContext中的onRefresh()方法:负责启动Tomcat

你可能感兴趣的:(微服务,spring,boot,java,spring)