SpringBoot(十二)启动流程分析之创建应用上下文AnnotationConfigServletWebServerApplicationContext

SpringBoot版本:2.1.1      ==》启动流程分析汇总

接上篇博客Spring Boot 2.1.1(十一)启动流程分析之设置系统属性spring.beaninfo.ignore、自定义banner图 

目录

流程分析

1、AbstractApplicationContext

2、GenericApplicationContext

2.1、DefaultListableBeanFactory

2.2、bean实例化策略

3、AnnotationConfigServletWebServerApplicationContext

3.1、实例化AnnotatedBeanDefinitionReader

3.2、实例化ClassPathBeanDefinitionScanner

总结


public ConfigurableApplicationContext run(String... args) {
            .... 
	try {
            //本篇内容从本行开始记录
           context = createApplicationContext();
	
           //本篇内容记录到这,后续更新
            ....
        }
	catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, listeners);
		throw new IllegalStateException(ex);
	}
}

流程分析

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";
 
 
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
			+ "annotation.AnnotationConfigApplicationContext";

protected ConfigurableApplicationContext createApplicationContext() {
	Class contextClass = this.applicationContextClass;
        //判断当前applicationContextClass是否为空,为空则根据web应用类型创建上下文
	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);
		}
	}
        //最终转换成是ConfigurableApplicationContext
	return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
 

根据应用类型创建对应的ApplicationContext对象,这里最终创建的是AnnotationConfigServletWebServerApplicationContext。

要了解AnnotationConfigServletWebServerApplicationContext的实例化过程中都做了什么,先要了解其继承结构。下面是其类图。

SpringBoot(十二)启动流程分析之创建应用上下文AnnotationConfigServletWebServerApplicationContext_第1张图片

会先从父类开始加载,追寻构造方法一直到AbstractApplicationContext。只在AbstractApplicationContextGenericApplicationContext、以及AnnotationConfigServletWebServerApplicationContext中构造方法执行了操作。下面一个一个记录执行的操作。

1、AbstractApplicationContext

AbstractApplicationContext中会做一些初始化,包括:

  1. 会得到Log对象
  2. 为上下文设置唯一id和显示名称
  3. 初始化BeanFactoryPostProcessors 的List集合
  4. 是否活跃标识active,1为true,0为false
  5. 是否已关闭标识closed,1为true,0为false
  6. 刷新和销毁的同步对象startupShutdownMonitor
  7. 初始化ApplicationListener的Set集合
  8. 在构造方法中实例化一个ServletContextResourcePatternResolver,参数就是AnnotationConfigServletWebServerApplicationContext

在构造方法中调用的方法是子类GenericWebApplicationContext重写后的方法。 将AnnotationConfigServletWebServerApplicationContext作为一个resourceLoader传递到父类。  

父类PathMatchingResourcePatternResolver是一个Ant模式通配符的Resource查找器,可以用来查找类路径下或者文件系统中的资源。在其中会实例化一个AntPathMatcher,该类实现Ant风格的路径模式。 

 解释一下BeanFactoryPostProcessors接口:

BeanFactoryPostProcessors:通过实现该接口,重写postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)方法,可以在bean未实例化之前通过beanFactory得到bean定义,并可以修改属性值。

2、GenericApplicationContext

然后在GenericApplicationContext中同样会做一些初始化,包括:

  1. 是否刷新标识refreshed,1为true,0为false
  2. customClassLoader = false
  3. 在构造方法中会实例化一个DefaultListableBeanFactory

官方注释里说了,GenericApplicationContext与为每次刷新创建新的内部beanfactory实例的其他applicationContext实现不同,此上下文的内部beanfactory从一开始就可用,以便能够在其上注册bean定义。只能调用一次refresh()。

在后面刷新上下文的时候,相对于其他上下文在每次刷新的时候都重新创建一个BeanFactory,GenericApplicationContext则不用,在其刷新BeanFactory的方法中,方法上的注释说了Do nothing,什么都不做。在后面的上下文刷新中会详细记录。

2.1、DefaultListableBeanFactory

DefaultListableBeanFactory的类图如下(跟上面的类图本想画在一起的,奈何wps要会员,就只能画在另一个里面了):

SpringBoot(十二)启动流程分析之创建应用上下文AnnotationConfigServletWebServerApplicationContext_第2张图片

 同样会先从父类SimpleAliasRegistry开始加载。其中会初始化各种集合,包括存放单例bean对象,单例工厂bean,已注册的单例bean,已创建过的bean名称,bean定义等等以及接口集合,如BeanPostProcessor。具体的话看类图吧。

再看下BeanFactory接口的官方注释:

SpringBoot(十二)启动流程分析之创建应用上下文AnnotationConfigServletWebServerApplicationContext_第3张图片

大概意思是:用于访问SpringBean容器的根接口。这是bean容器的基本客户机视图;其他接口(如listablebeanfactory和configurablebeanfactory)可用于特定目的。这个接口是由持有许多bean定义的对象实现的,每个定义都由一个字符串名称唯一标识。根据bean定义,工厂将返回包含对象的独立实例(原型模式)或单个共享实例(与工厂范围内的单个实例为单例的单例模式相比,这是一种更好的选择)。返回哪种类型的实例取决于bean工厂配置:API是相同的。自Spring2.0以来,根据具体的应用程序上下文(例如Web环境中的“请求”和“会话”范围),可以使用更多的范围。

SpringBoot(十二)启动流程分析之创建应用上下文AnnotationConfigServletWebServerApplicationContext_第4张图片

大概意思是:

bean工厂实现应该尽可能支持标准bean生命周期接口。整套初始化方法及其标准顺序为:

  1. BeanNameAware's {@code setBeanName}
  2. BeanClassLoaderAware's {@code setBeanClassLoader}
  3. BeanFactoryAware's {@code setBeanFactory}
  4. EnvironmentAware's {@code setEnvironment}
  5. EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}
  6. ResourceLoaderAware's {@code setResourceLoader}(only applicable when running in an application context)
  7. ApplicationEventPublisherAware's {@code setApplicationEventPublisher}(only applicable when running in an application context)
  8. MessageSourceAware's {@code setMessageSource}(only applicable when running in an application context)
  9. ApplicationContextAware's {@code setApplicationContext}(only applicable when running in an application context)
  10. ServletContextAware's {@code setServletContext}(only applicable when running in a web application context)
  11. {@code postProcessBeforeInitialization} methods of BeanPostProcessors
  12. InitializingBean's {@code afterPropertiesSet}
  13. a custom init-method definition
  14. {@code postProcessAfterInitialization} methods of BeanPostProcessors

在bean工厂关闭时,应用以下生命周期方法:

  1. {@code postProcessBeforeDestruction} methods of DestructionAwareBeanPostProcessors
  2. DisposableBean's {@code destroy}
  3. a custom destroy-method definition

BeanDefinitionRegistry:包含bean定义的注册表接口,例如RootBeanDefinition和ChildBeanDefinition实例。通常由Bean工厂实现,Bean工厂内部使用AbstractBeanDefinition层次结构。这是Spring的bean工厂包中唯一封装bean定义注册的接口 。标准BeanFactory接口仅涵盖对完全配置的工厂实例的访问。Spring的bean definition readers希望能够在这个接口的实现上工作。Spring中已知的核心实现是DefaultListableBeanFactory和GenericApplicationContext。

2.2、bean实例化策略

AbstractAutowireCapableBeanFactory中实例化了一个InstantiationStrategy接口的实现类对象,bean实例化策略,

 根接口InstantiationStrategy只有三个重载方法。

继承结构如下: 

SpringBoot(十二)启动流程分析之创建应用上下文AnnotationConfigServletWebServerApplicationContext_第5张图片

可以看到重写了上面的三个方法。 

SpringBoot(十二)启动流程分析之创建应用上下文AnnotationConfigServletWebServerApplicationContext_第6张图片

挑一个短一点的方法看一下,如果没有方法重写,不需要生成cglib动态生成子类。否则就是调用的下面的方法,下面的instantiateWithMethodInjection方法是一个空方法。方法上的注释意思是:如果子类可以用给定rootbeanDefinition中指定的方法注入来实例化对象,则子类可以重写此方法,该方法实现为引发UnsupportedOperationException。实例化应该使用给定的构造函数和参数。

SpringBoot(十二)启动流程分析之创建应用上下文AnnotationConfigServletWebServerApplicationContext_第7张图片

在看下子类重写的instantiateWithMethodInjection方法。只是稍微看下里面的内容。具体看调用的地方。

SpringBoot(十二)启动流程分析之创建应用上下文AnnotationConfigServletWebServerApplicationContext_第8张图片

 调用instantiate方法,然后再该方法内判断使用哪种实例化策略。可能表达的意思不是很好,主要想说就是这里是一种设计模式,策略模式

 

3、AnnotationConfigServletWebServerApplicationContext

在构造方法中会实例化两个类,分别是AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner。

3.1、实例化AnnotatedBeanDefinitionReader

看一下官方注释:

 大概意思:方便的适配器,用于编程注册带注释的bean类。这是@link classpathbeanddefinitionscanner的替代方案,应用相同的注释解析,但仅限于显式注册的类。

在这个类中会实例化一个AnnotationBeanNameGenerator和一个AnnotationScopeMetadataResolver。

AnnotationBeanNameGenerator见名知意,生成beanName。如果属于注解bean定义,即获取注解定义的beanName,不是就获取默认的beanName,即类名首字母小写。isStereotypeWithNameValue()方法会判断注解类型是否是Component或者元注解中是否有Component或者注解类型是否是ManagedBean和Named,且attributes不为空,attributes存在value值。

SpringBoot(十二)启动流程分析之创建应用上下文AnnotationConfigServletWebServerApplicationContext_第9张图片

 AnnotationScopeMetadataResolver即Scope注解元数据解析。扫描Scope注解并设置值。

 是否属于注解定义,是就转为注解定义并得到attributes对象,该对象包含了注解信息,如果attributes不为空,得到value值即Scope的取值,并设置到ScopeName,再设置代理模式,最后返回Scopemetadata对象。

SpringBoot(十二)启动流程分析之创建应用上下文AnnotationConfigServletWebServerApplicationContext_第10张图片

构造方法

上面看官方注释的时候说了方便的适配器,在构造方法中的参数类型是BeanDefinitionRegistry,实际传进来的是AnnotationConfigServletWebServerApplicationContext,这就是对象的适配。通过看类图可以知道AnnotationConfigServletWebServerApplicationContext的父类GenericApplicationContext实现了BeanDefinitionRegistry接口。所以这里AnnotationConfigServletWebServerApplicationContext可以被当做一个registry。

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
	Assert.notNull(environment, "Environment must not be null");
        //用于bean定义注册
	this.registry = registry;
        //用于判断是否跳过bean注册,用于判断Condition注解
	this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
        //在这一步会注册几个bean定义
	AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

 在registerAnnotationConfigProcessors()方法中,设置了DependencyComparator(依赖比较器),AutowireCandidateResolver(Autowire注解候选解析,即解析@Qualifier注解),以及注册了几个bean定义。AnnotationConfigServletWebServerApplicationContext被当做registry用来注册bean定义,实际调用的是DefaultListableBeanFactory的registerBeanDefinition方法。

public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
	registerAnnotationConfigProcessors(registry, null);
}
public static Set registerAnnotationConfigProcessors(
		BeanDefinitionRegistry 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 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;
}

注册的bean如下 :

  1. ConfigurationClassPostProcessor
  2. AutowiredAnnotationBeanPostProcessor
  3. CommonAnnotationBeanPostProcessor
  4. EventListenerMethodProcessor
  5. DefaultEventListenerFactory

这些注册的bean会在后面的流程中被调用。

3.2、实例化ClassPathBeanDefinitionScanner

同样先看下官方注释

SpringBoot(十二)启动流程分析之创建应用上下文AnnotationConfigServletWebServerApplicationContext_第11张图片

大概意思:

一个bean定义扫描器,用于检测类路径上的bean候选项,并在给定的注册表(@code beanfactory或@code applicationContext)中注册相应的bean定义。

通过可配置的类型过滤器检测候选类。默认过滤器包括用Spring的@Component、@Repository、@Service、@Controller注释的类。

同样支持JavaEE 6的ManagedBean和JSR-330的Named注解,如果有的话。

该类中同样有BeanDefinitionRegistry,AnnotationBeanNameGenerator,AnnotationScopeMetadataResolver对象。

构造方法

在父类ClassPathScanningCandidateComponentProvider中初始化了两个final修饰的list,分别是List includeFilters和List excludeFilters。这两个List对象在isCandidateComponent()方法中充当过滤规则。

SpringBoot(十二)启动流程分析之创建应用上下文AnnotationConfigServletWebServerApplicationContext_第12张图片

在registerDefaultFilters()方法中就往includeFilters中注册Filter,注册的是AnnotationTypeFilter,过滤的注解就是前面注释里讲的@Component、@Repository、@Service、@Controller和JavaEE 6的ManagedBean和JSR-330的Named注解。

然后就是设置环境,设置ResourceLoader。

到这AnnotationConfigServletWebServerApplicationContext创建过程就走完了。在创建上下文中注册的bean只有这五个,即在实例化AnnotatedBeanDefinitionReader的时候注册的。

SpringBoot(十二)启动流程分析之创建应用上下文AnnotationConfigServletWebServerApplicationContext_第13张图片

总结

回顾一下流程:

AbstractApplicationContext中会做一些初始化,包括:

  1. 会得到Log对象
  2. 为上下文设置唯一id和显示名称
  3. 初始化BeanFactoryPostProcessors 的List集合
  4. 是否活跃标识active,1为true,0为false
  5. 是否已关闭标识closed,1为true,0为false
  6. 刷新和销毁的同步对象startupShutdownMonitor
  7. 初始化ApplicationListener的Set集合
  8. 在构造方法中实例化一个ServletContextResourcePatternResolver,参数就是AnnotationConfigServletWebServerApplicationContext

GenericApplicationContext中同样会做一些初始化,包括:

  1. 是否刷新标识refreshed,1为true,0为false
  2. customClassLoader = false
  3. 在构造方法中会实例化一个DefaultListableBeanFactory

在AnnotationConfigServletWebServerApplicationContext中:

  1. 实例化AnnotatedBeanDefinitionReader
  2. 实例化ClassPathBeanDefinitionScanner

你可能感兴趣的:(springboot,SpringBoot学习记录)