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的实例化过程中都做了什么,先要了解其继承结构。下面是其类图。
会先从父类开始加载,追寻构造方法一直到AbstractApplicationContext。只在AbstractApplicationContext、GenericApplicationContext、以及AnnotationConfigServletWebServerApplicationContext中构造方法执行了操作。下面一个一个记录执行的操作。
在AbstractApplicationContext中会做一些初始化,包括:
在构造方法中调用的方法是子类GenericWebApplicationContext重写后的方法。 将AnnotationConfigServletWebServerApplicationContext作为一个resourceLoader传递到父类。
父类PathMatchingResourcePatternResolver是一个Ant模式通配符的Resource查找器,可以用来查找类路径下或者文件系统中的资源。在其中会实例化一个AntPathMatcher,该类实现Ant风格的路径模式。
解释一下BeanFactoryPostProcessors接口:
BeanFactoryPostProcessors:通过实现该接口,重写postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)方法,可以在bean未实例化之前通过beanFactory得到bean定义,并可以修改属性值。
然后在GenericApplicationContext中同样会做一些初始化,包括:
官方注释里说了,GenericApplicationContext与为每次刷新创建新的内部beanfactory实例的其他applicationContext实现不同,此上下文的内部beanfactory从一开始就可用,以便能够在其上注册bean定义。只能调用一次refresh()。
在后面刷新上下文的时候,相对于其他上下文在每次刷新的时候都重新创建一个BeanFactory,GenericApplicationContext则不用,在其刷新BeanFactory的方法中,方法上的注释说了Do nothing,什么都不做。在后面的上下文刷新中会详细记录。
DefaultListableBeanFactory的类图如下(跟上面的类图本想画在一起的,奈何wps要会员,就只能画在另一个里面了):
同样会先从父类SimpleAliasRegistry开始加载。其中会初始化各种集合,包括存放单例bean对象,单例工厂bean,已注册的单例bean,已创建过的bean名称,bean定义等等以及接口集合,如BeanPostProcessor。具体的话看类图吧。
再看下BeanFactory接口的官方注释:
大概意思是:用于访问SpringBean容器的根接口。这是bean容器的基本客户机视图;其他接口(如listablebeanfactory和configurablebeanfactory)可用于特定目的。这个接口是由持有许多bean定义的对象实现的,每个定义都由一个字符串名称唯一标识。根据bean定义,工厂将返回包含对象的独立实例(原型模式)或单个共享实例(与工厂范围内的单个实例为单例的单例模式相比,这是一种更好的选择)。返回哪种类型的实例取决于bean工厂配置:API是相同的。自Spring2.0以来,根据具体的应用程序上下文(例如Web环境中的“请求”和“会话”范围),可以使用更多的范围。
大概意思是:
bean工厂实现应该尽可能支持标准bean生命周期接口。整套初始化方法及其标准顺序为:
在bean工厂关闭时,应用以下生命周期方法:
BeanDefinitionRegistry:包含bean定义的注册表接口,例如RootBeanDefinition和ChildBeanDefinition实例。通常由Bean工厂实现,Bean工厂内部使用AbstractBeanDefinition层次结构。这是Spring的bean工厂包中唯一封装bean定义注册的接口 。标准BeanFactory接口仅涵盖对完全配置的工厂实例的访问。Spring的bean definition readers希望能够在这个接口的实现上工作。Spring中已知的核心实现是DefaultListableBeanFactory和GenericApplicationContext。
在AbstractAutowireCapableBeanFactory中实例化了一个InstantiationStrategy接口的实现类对象,bean实例化策略,
根接口InstantiationStrategy只有三个重载方法。
继承结构如下:
可以看到重写了上面的三个方法。
挑一个短一点的方法看一下,如果没有方法重写,不需要生成cglib动态生成子类。否则就是调用的下面的方法,下面的instantiateWithMethodInjection方法是一个空方法。方法上的注释意思是:如果子类可以用给定rootbeanDefinition中指定的方法注入来实例化对象,则子类可以重写此方法,该方法实现为引发UnsupportedOperationException。实例化应该使用给定的构造函数和参数。
在看下子类重写的instantiateWithMethodInjection方法。只是稍微看下里面的内容。具体看调用的地方。
调用instantiate方法,然后再该方法内判断使用哪种实例化策略。可能表达的意思不是很好,主要想说就是这里是一种设计模式,策略模式。
在构造方法中会实例化两个类,分别是AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner。
看一下官方注释:
大概意思:方便的适配器,用于编程注册带注释的bean类。这是@link classpathbeanddefinitionscanner的替代方案,应用相同的注释解析,但仅限于显式注册的类。
在这个类中会实例化一个AnnotationBeanNameGenerator和一个AnnotationScopeMetadataResolver。
AnnotationBeanNameGenerator见名知意,生成beanName。如果属于注解bean定义,即获取注解定义的beanName,不是就获取默认的beanName,即类名首字母小写。isStereotypeWithNameValue()方法会判断注解类型是否是Component或者元注解中是否有Component或者注解类型是否是ManagedBean和Named,且attributes不为空,attributes存在value值。
AnnotationScopeMetadataResolver即Scope注解元数据解析。扫描Scope注解并设置值。
是否属于注解定义,是就转为注解定义并得到attributes对象,该对象包含了注解信息,如果attributes不为空,得到value值即Scope的取值,并设置到ScopeName,再设置代理模式,最后返回Scopemetadata对象。
构造方法
上面看官方注释的时候说了方便的适配器,在构造方法中的参数类型是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如下 :
这些注册的bean会在后面的流程中被调用。
同样先看下官方注释
大概意思:
一个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
在registerDefaultFilters()方法中就往includeFilters中注册Filter,注册的是AnnotationTypeFilter,过滤的注解就是前面注释里讲的@Component、@Repository、@Service、@Controller和JavaEE 6的ManagedBean和JSR-330的Named注解。
然后就是设置环境,设置ResourceLoader。
到这AnnotationConfigServletWebServerApplicationContext创建过程就走完了。在创建上下文中注册的bean只有这五个,即在实例化AnnotatedBeanDefinitionReader的时候注册的。
回顾一下流程:
在AbstractApplicationContext中会做一些初始化,包括:
在GenericApplicationContext中同样会做一些初始化,包括:
在AnnotationConfigServletWebServerApplicationContext中: