从servlet到springboot(6) springboot启动 run方法解析之prepareContext

上节我们分析到analyzers = new FailureAnalyzers(context);为止

我们接下去分析prepareContext

这段代码主要做了八件事

为上下文设置Environment. 注意 这里传入的是 StandardServletEnvironment

调用postProcessApplicationContext方法设置上下文的beanNameGenerator和resourceLoader(如果SpringApplication有的话)

拿到之前实例化SpringApplication对象的时候设置的ApplicationContextInitializer,调用它们的initialize方法,对上下文做初始化
调用listeners#contextPrepared,该方法是一个空实现
打印启动日志
往上下文的beanFactory中注册一个singleton的bean,bean的名字是springApplicationArguments,bean的实例是之前实例化的ApplicationArguments对象, 
如果之前获取的printedBanner不为空,那么往上下文的beanFactory中注册一个singleton的bean,bean的名字是springBootBanner,bean的实例就是这个printedBanner.这里默认是SpringBootBanner.
调用load方法注册启动类的bean定义,也就是调用SpringApplication.run(Application.class, args);的类,SpringApplication的load方法内会创建BeanDefinitionLoader的对象,并调用它的load()方法
调用listeners的contextLoaded方法,说明上下文已经加载,该方法先找到所有的ApplicationListener,遍历这些listener,如果该listener继承了ApplicationContextAware类,那么在这一步会调用它的setApplicationContext方法,设置context
我们一句句分析

先看第一句话

context.setEnvironment(environment);

这句话没什么好说的,就是设置一些变量

postProcessApplicationContext(context);

SpringApplication#prepareContext 接下来执行的是 postProcessApplicationContext 方法.设置上下文的beanNameGenerator和resourceLoader(如果SpringApplication有的话).

applyInitializers(context);

----->

首先是获取到在SpringApplication中初始化的,Initializers,一共有六个,然后循环遍历他们的initialize方法。这里分析几个Initializers

DelegatingApplicationContextInitializer#initialize 会根据环境中有没有context.initializer.classes的配置项,来加载,这是一个扩展点,spring本身是没有的,需要我们自行配置,如果有的就会实例化,然后再调用他的initialize

ContextIdApplicationContextInitializer#initialize 这个方法就是设置contextId,具体规则不深究

ServerPortInfoApplicationContextInitializer#initialize 这个向applicationContext 添加一个监听.当发生EmbeddedServletContainerInitializedEvent事件时.会执行ServerPortInfoApplicationContextInitializer#onApplicationEvent方法.将server.ports添加到名为server.ports 的MapPropertySource

SharedMetadataReaderFactoryContextInitializer#initialize向applicationContext 添加了一个CachingMetadataReaderFactoryPostProcessor 的BeanFactoryPostProcessor 至于BeanFactoryPostProcessor的具体讲解,我们会在refresh方法中进行讲解。

剩余的Initializer就不说了

视线回到prepareContext方法,listeners.contextPrepared(context);这里是个空实现,EventPublishingRunListeners没有具体实现这个方法。

接着这段代码是打印相关日志。
if (this.logStartupInfo) {
   logStartupInfo(context.getParent() == null);
//配置项相关日志
   logStartupProfileInfo(context);
}

然后再spring容器中添加一些bean,我们直接看load方法

load(context, sources.toArray(new Object[sources.size()]));

这里的source就是启动类

直接跳到BeanDefinitionLoader方法中的

private int load(Class<?> source) {
   if (isGroovyPresent()) {
      // Any GroovyLoaders added in beans{} DSL can contribute beans here
      if (GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
         GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,
               GroovyBeanDefinitionSource.class);
         load(loader);
      }
   }
   if (isComponent(source)) {
      this.annotatedReader.register(source);
      return 1;
   }
   return 0;
}

由于启动类中有configuration注解,所以是一个component注解类

public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
   AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
   if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
      return;
   }

   ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
   abd.setScope(scopeMetadata.getScopeName());
   String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
   AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
   if (qualifiers != null) {
      for (Class<? extends Annotation> qualifier : qualifiers) {
         if (Primary.class == qualifier) {
            abd.setPrimary(true);
         }
         else if (Lazy.class == qualifier) {
            abd.setLazyInit(true);
         }
         else {
            abd.addQualifier(new AutowireCandidateQualifier(qualifier));
         }
      }
   }

   BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
   definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
   BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

我们慢慢跟踪

this.conditionEvaluator.shouldSkip(abd.getMetadata())

该代码判断Application上是否存在Conditional注解,如果不满足Conditional对应条件则该bean不被创建

Conditional注解
代码分析到这里可以先看看Conditional注解的使用,其定义为:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Conditional {
    /**
     * All {@link Condition}s that must {@linkplain Condition#matches match}
     * in order for the component to be registered.
     */
    Class<? extends Condition>[] value();
 
}

从源码可以看出,首先判断Application上是否存在Conditional,如果存在,则获取Conditional注解中的value数组值,对应的Class必须实现Condition接口:

public interface Condition { 
    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
 
}

如果matches返回true 表明该bean需要被创建,否则表明该bean不需要被创建。

明白了该注解的用法后,来一个实际案例
package com.lkl.springboot.condition;
 
import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Component;
 
@Component("MyCondition")
@Conditional(MyCondition.class)
public class ConditionBean {
}

创建ConditionBean,使用注解@Conditional(MyCondition.class)调用MyCondition类

/**
 * 自定义condition  修改返回值,查看bean是否创建
 * 
 * @author liaokailin
 */
public class MyCondition implements Condition {
 
    /**
     * 返回true 生成bean
     * 返回false 不生成bean 
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Map<String, Object> map = metadata.getAnnotationAttributes(Component.class.getName());
        return "MyCondition".equals(map.get("value").toString());
    }
 
}

MyCondition实现接口Condition,在matches方法中获取bean上注解Component信息,如果bean名称等于MyCondition返回true,否则返回false,bean不会被创建。

回到前面Application的分析,Application上不存在Conditional,因此shouldSkip返回false,代码继续执行

ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);

单例相关

AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);

这个方法比较复杂,总结一下就是处理一下常见的注解

处理Lazy、Primary、DependsOn、Role、Description等注解

直接跳到最后一步,把mian主类注册到spring容器中,也就是加入到beanDefinitionMap里面

BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);

视线回到prepareContext中

listeners.contextLoaded(context);

这里其实是调用EventPublishingRunListners的contextLoaded方法

public void contextLoaded(ConfigurableApplicationContext context) {
    for (ApplicationListener<?> listener : this.application.getListeners()) {
        if (listener instanceof ApplicationContextAware) {
            ((ApplicationContextAware) listener).setApplicationContext(context);
        }
        context.addApplicationListener(listener);
    }
    this.initialMulticaster.multicastEvent(
            new ApplicationPreparedEvent(this.application, this.args, context));
}

this.application.getListeners()这句话是老面孔,还是那10个linsteners,然后循环遍历,调用onApplicationEvent方法,此时发布的事件是ApplicationPreparedEvent类型事件

这一节完毕。。下一节我们将分析refresh方法,这是spring的重头戏。。将分成好几节讲

猜你喜欢

转载自blog.csdn.net/m0_37139189/article/details/86293761
今日推荐