首页 > 编程语言 > 详细

(三)SpringBoot启动过程的分析-创建应用程序上下文

时间:2021-03-30 22:16:35      阅读:42      评论:0      收藏:0      [点我收藏+]

-- 以下内容均基于2.1.8.RELEASE版本

紧接着上一篇(二)SpringBoot启动过程的分析-环境信息准备,本文将分析环境准备完毕之后的下一步操作:ApplicationContext的创建。

创建指定类型的应用程序上下文容器

// SpringApplication.java

ConfigurableApplicationContext context = createApplicationContext();

protected ConfigurableApplicationContext createApplicationContext() {
	// ①
	Class<?> contextClass = this.applicationContextClass;
	if (contextClass == null) {
		try {
			switch (this.webApplicationType) {
			case SERVLET:
				// ②
				contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
				break;
			case REACTIVE:
				// ③
				contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
				break;
			default:
				// ④
				contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
			}
		}
		catch (ClassNotFoundException ex) {
			throw new IllegalStateException("Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass", ex);
		}
	}
	// ⑤
	return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

创建ApplicationContext时可以指定需要创建的上下文类型,默认是根据当前应用类型来创建。在SpringApplication.java中指定了几种默认类型,他们分别是默认的非Web应用上下文容器、默认的Web应用上下文容器和响应式Web上下文容器

public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context." + "annotation.AnnotationConfigApplicationContext";
public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot." + "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework." + "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";

① - 是否有指定的ApplicationContext,若有直接实例化
② - 实例化Web应用上下文容器
③ - 实例化响应式Web应用上下文容器
④ - 实例化非Web应用上下文容器
⑤ - 使用无参构造函数对指定的上下文容器进行实例化

AnnotationConfigServletWebServerApplicationContext

对于常规的以SpringBoot开发的web应用来说,AnnotationConfigServletWebServerApplicationContext将会是默认的上下文容器。它可以解析@Configuration等JSR-330定义的注解,查看它的包路径,可以看到,它是属于SpringBoot下的上下文容器。

public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {

	private final AnnotatedBeanDefinitionReader reader;

	private final ClassPathBeanDefinitionScanner scanner;

	private final Set<Class<?>> annotatedClasses = new LinkedHashSet<>();

	private String[] basePackages;


	public AnnotationConfigServletWebServerApplicationContext() {
		// ①
		this.reader = new AnnotatedBeanDefinitionReader(this);
		// ②
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}
}

① - 构造AnnotatedBeanDefinitionReader,传入当前对象作为Bean注册器
② - 构造ClassPathBeanDefinitionScanner,传入当前对象作为Bean注册器

它内部的无参构造方法就干了两件事:初始化reader和scanner。他们两个的存在使当前的上下文容器支持以带有@Configuration注解的类作为加载Bean入口,也支持以指定的basePackage来作为加载Bean的入口,同时还支持注解的过滤。

上下文容器重要成员之 AnnotatedBeanDefinitionReader

用编程方式注册带注解的Bean到容器中,也就是基于注解配置的Bean的注册。

public class AnnotatedBeanDefinitionReader {

	// ①
	private final BeanDefinitionRegistry registry;

	// ②
	private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();

	// ③
	private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
	
	// ④
	private ConditionEvaluator conditionEvaluator;

	// ⑤
	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
		this(registry, getOrCreateEnvironment(registry));
	}
	// ...省略部分代码
}

① - BeanDefinition注册器
② - BeanName生成器
③ - Bean的作用域元数据解析器
④ - 条件注解评估器,用于判断是否跳过被条件注解修饰的类的加载
⑤ - 通过Bean注册器来构造Reader

注册内定的PostProcessor

在初始化AnnotatedBeanDefinitionReader的时候,将一些用于作基础处理的类处理器优先注册到容器内部,不太明白也没关系,照着代码看下去,看完几个就明白是干什么的了。

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
	Assert.notNull(environment, "Environment must not be null");
	this.registry = registry;
	this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
	// 注册一些固定的内部指定的类到容器中
	AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
	registerAnnotationConfigProcessors(registry, null);
}

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( registry, @Nullable Object source) {

	DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
	
	if (beanFactory != null) {
		// ①
		if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
			beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
		}
		// ②
		if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
			beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
		}
	}

	// ③
	Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

	if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
	if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
	if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition();
		try {
			def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, AnnotationConfigUtils.class.getClassLoader()));
		}
		catch (ClassNotFoundException ex) {
			throw new IllegalStateException("Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
		}
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
	}

	if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
	}

	return beanDefs;
}

① - 给BeanFactory添加AnnotationAwareOrderComparator,用于处理Bean的排序
② - 给BeanFactory添加ContextAnnotationAutowireCandidateResolver,用于处理@Lazy注解和@Qualifier注解
③ - 注册指定的类到容器

SpringBoot默认优先注册了以下PostProcessor类,并以不同的名称来称呼这些类:
左边的为BeanDefinition的名称,右边为对应的类,名称的前缀都统一是org.springframework.context.annotation

  1. 由Spring内部管理的用于处理配置注解的处理器
    internalConfigurationAnnotationProcessor -> ConfigurationClassPostProcessor.class

  2. 由Spring内部管理的用于处理自动装配注解的处理器
    internalAutowiredAnnotationProcessor -> AutowiredAnnotationBeanPostProcessor.class

  3. 由Spring内部管理的用于处理JSR-250注解的处理器
    internalCommonAnnotationProcessor -> CommonAnnotationBeanPostProcessor.class

  4. 由Spring内部管理的用于处理JPA注解的处理器
    internalPersistenceAnnotationProcessor -> PersistenceAnnotationBeanPostProcessor.class

  5. 由Spring内部管理的用于处理@EventListener注解的处理器
    internalEventListenerProcessor -> EventListenerMethodProcessor.class

  6. 由Spring内部管理的用于指定EventListenerFactory默认实现的类
    internalEventListenerFactory -> DefaultEventListenerFactory.class

其实看到这里就明白许多,单纯的就是Spring固定了一些类要首先注册进去容器,也就是在处理注解的Reader准备完毕的时候,它已经准备好了一些后续要使用的类,他们用于在不同阶段来处理不同的事情。至于注册的这些类分别可以完成什么工作,将在他们真正开始执行的时候再进行分析。至此AnnotatedBeanDefinitionReader的初始化完成了。

上下文容器重要成员之 ClassPathBeanDefinitionScanner

和上面的Reader不同的是它用于扫描类路径上的Bean,通过给定的basePackage路径来扫描类。它可以使用可配置的过滤器来检测候选类,已确定他们将是否被加载。默认的过滤器包括Spring框架的@Component、@Controller、@Service、@Repository

// 构造方法一
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
	this(registry, true);
}

// 构造方法二
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
	this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
}

// 构造方法三
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
		Environment environment) {

	this(registry, useDefaultFilters, environment,
			(registry instanceof ResourceLoader ? (ResourceLoader) registry : null));
}

// 构造方法四
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment, @Nullable ResourceLoader resourceLoader) {

	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
	this.registry = registry;
	// 使用默认过滤器,从构造方法一直接传入true,代表它是默认的。
	if (useDefaultFilters) {
		// 注册默认过滤器
		registerDefaultFilters();
	}
	// 设置环境对象和资源加载器
	setEnvironment(environment);
	setResourceLoader(resourceLoader);
}

通过多个重载的构造方法来构造ClassPathBeanDefinitionScanner对象。最后一个实际使用的构造方法传入了类注册器、是否使用默认过滤器、环境对象、资源加载器。若传入的是一个普通的BeanDefinitionRegistry(实现了BeanDefinitionRegistry接口但没有实现ResourceLoader接口的类)那么默认的资源加载器将会是org.springframework.core.io.support.PathMatchingResourcePatternResolver.

注册默认注解过滤器

为@Component注册过滤器, 还会隐式的注册@Controller、@Service、@Repository。为何说是隐式的呢?查看这几个注解便知。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {

	@AliasFor(annotation = Component.class)
	String value() default "";
}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {

	@AliasFor(annotation = Component.class)
	String value() default "";
}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {

	@AliasFor(annotation = Component.class)
	String value() default "";

}

他同时使用了@Component注解,并将别名设置为Component.class

// ClassPathScanningCandidateComponentProvider.java

protected void registerDefaultFilters() {
	// 新增Component注解过滤器(包含Controller、Service、Repository)
	this.includeFilters.add(new AnnotationTypeFilter(Component.class));
	ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
	try {
		// 如果可用的话,支持JSR-250的ManagedBean注解过滤器
		this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
		logger.trace("JSR-250 ‘javax.annotation.ManagedBean‘ found and supported for component scanning");
	}
	catch (ClassNotFoundException ex) {
		// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
	}
	try {
		// 如果可用的话,支持JSR-330支持的Named注解过滤器
		this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
		logger.trace("JSR-330 ‘javax.inject.Named‘ annotation found and supported for component scanning");
	}
	catch (ClassNotFoundException ex) {
		// JSR-330 API not available - simply skip.
	}
}

总结

在上下文容器创建完毕且未刷新的情况下,内部已经优先注册了一批PostProcessor,毫无疑问,他们将会在容器接下来的操作中扮演重要角色。这里只需要理解容器在程序运行的不同阶段会有不同的执行逻辑。大概知晓它在创建的时候做了什么,在后续文章中会逐步分析。

(三)SpringBoot启动过程的分析-创建应用程序上下文

原文:https://www.cnblogs.com/lukama/p/14525282.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!