有道无术,术尚可求,有术无道,止于术。
本系列Spring Boot版本2.7.0
前言
紧接上文,下一步是创建和准备上下文
context = this.createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
核心类
ServletWebServerApplicationContext
ServletWebServerApplicationContext 从名字上看,它是一个基于Servlet Web 服务的应用上下文,它的类图如下: 它是Spring Boot 提供的基于Servlet 开发时使用的一个IOC容器,从它的类继承可以看出,它依赖于Spring MVC,而且还提供了两个子类,从名字就知道一个是基于注解,一个是基于XML注册的容器。
AnnotatedBeanDefinitionReader ClassPathBeanDefinitionScanner
AnnotatedBeanDefinitionReader 从名字上理解,是一个注解方式的BeanDefinition 读取器,学过Spring 的都知道首先会加载BeanDefinition ,然后根据BeanDefinition 生成Bean 对象,这个类的主要作用就是就是加载BeanDefinition 了。
ClassPathBeanDefinitionScanner 的作用也是加载BeanDefinition ,不过从它的名字中,我们知道是一个扫描指定类路径中的BeanDefinition 扫描器。
上面这两个类作用都是Bean 定义的加载。
1. 创建应用上下文
createApplicationContext 方法直接调用工厂类创建对象:
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.create(this.webApplicationType);
}
这个工厂类是SpringApplication 类的成员属性,是ApplicationContextFactory 的内部类DEFAULT :
this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
所以直接进入了ApplicationContextFactory 的内部匿名实现类中:
ApplicationContextFactory DEFAULT = (webApplicationType) -> {
try {
for (ApplicationContextFactory candidate : SpringFactoriesLoader
.loadFactories(ApplicationContextFactory.class, ApplicationContextFactory.class.getClassLoader())) {
ConfigurableApplicationContext context = candidate.create(webApplicationType);
if (context != null) {
return context;
}
}
return AotDetector.useGeneratedArtifacts() ? new GenericApplicationContext()
: new AnnotationConfigApplicationContext();
}
catch (Exception ex) {
throw new IllegalStateException("Unable create a default ApplicationContext instance, "
+ "you may need a custom ApplicationContextFactory", ex);
}
};
进入到AnnotationConfigServletWebServerApplicationContext 内部类创建工厂时,因为类型为SERVLET ,所以会直接new 一个无参构造方法创建应用上下文对象:
public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
return webApplicationType != WebApplicationType.SERVLET ? null : new AnnotationConfigServletWebServerApplicationContext();
}
学过JAVA 的都知道,子类的构造函数会隐式调用父类的无参构造函数,所以我们先看下AnnotationConfigServletWebServerApplicationContext 的父类构造器中,都做了些什么。
首先是AbstractApplicationContext
public AbstractApplicationContext() {
this.logger = LogFactory.getLog(this.getClass());
this.id = ObjectUtils.identityToString(this);
this.displayName = ObjectUtils.identityToString(this);
this.beanFactoryPostProcessors = new ArrayList();
this.active = new AtomicBoolean();
this.closed = new AtomicBoolean();
this.startupShutdownMonitor = new Object();
this.applicationStartup = ApplicationStartup.DEFAULT;
this.applicationListeners = new LinkedHashSet();
this.resourcePatternResolver = this.getResourcePatternResolver();
}
接着是GenericApplicationContext :
public GenericApplicationContext() {
this.customClassLoader = false;
this.refreshed = new AtomicBoolean();
this.beanFactory = new DefaultListableBeanFactory();
}
接着到本类中:
public AnnotationConfigServletWebServerApplicationContext() {
this.annotatedClasses = new LinkedHashSet();
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
最后,通过构造函数,应用上下文就创建成功了,但是大部分属性都是NULL ,这个创建创建阶段只是完成了初始化对象的创建操作。
2. 准备上下文
接下来进入到prepareContext 准备上下文方法中:
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
this.postProcessApplicationContext(context);
this.applyInitializers(context);
listeners.contextPrepared(context);
bootstrapContext.close(context);
if (this.logStartupInfo) {
this.logStartupInfo(context.getParent() == null);
this.logStartupProfileInfo(context);
}
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
((AbstractAutowireCapableBeanFactory)beanFactory).setAllowCircularReferences(this.allowCircularReferences);
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
context.addBeanFactoryPostProcessor(new SpringApplication.PropertySourceOrderingBeanFactoryPostProcessor(context));
Set<Object> sources = this.getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
this.load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
在setEnvironment 方法中会将环境对象设置给上下文及读取器和扫描器:
public void setEnvironment(ConfigurableEnvironment environment) {
super.setEnvironment(environment);
this.reader.setEnvironment(environment);
this.scanner.setEnvironment(environment);
}
postProcessApplicationContext 方法只有最后一行代码实际执行了,设置ConversionService 给上下文中的Bean 工厂:
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
if (this.beanNameGenerator != null) {
context.getBeanFactory().registerSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator", this.beanNameGenerator);
}
if (this.resourceLoader != null) {
if (context instanceof GenericApplicationContext) {
((GenericApplicationContext)context).setResourceLoader(this.resourceLoader);
}
if (context instanceof DefaultResourceLoader) {
((DefaultResourceLoader)context).setClassLoader(this.resourceLoader.getClassLoader());
}
}
if (this.addConversionService) {
context.getBeanFactory().setConversionService(context.getEnvironment().getConversionService());
}
}
在applyInitializers 方法中会调用之前SPI 机制加载的ApplicationContextInitializer 的所有实例的初始化方法,
protected void applyInitializers(ConfigurableApplicationContext context) {
Iterator var2 = this.getInitializers().iterator();
while(var2.hasNext()) {
ApplicationContextInitializer initializer = (ApplicationContextInitializer)var2.next();
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
在之前我们了解过,一共有7 中应用初始化器,最先进入的是DelegatingApplicationContextInitializer ,之前我们说过,它是一个委托的初始化器,会加载context.initializer.classes 配置的初始化器,然后进行调用,代码如下: 第二个进入的是SharedMetadataReaderFactoryContextInitializer ,它的主要作用是创建了一个Bean 工厂后置处理器并设置到上下文中。
public void initialize(ConfigurableApplicationContext applicationContext) {
BeanFactoryPostProcessor postProcessor = new SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor(applicationContext);
applicationContext.addBeanFactoryPostProcessor(postProcessor);
}
第三个是ContextIdApplicationContextInitializer ,作用为创建一个ContextId 对象,并将其注册到Bean 工厂中,
public void initialize(ConfigurableApplicationContext applicationContext) {
ContextIdApplicationContextInitializer.ContextId contextId = this.getContextId(applicationContext);
applicationContext.setId(contextId.getId());
applicationContext.getBeanFactory().registerSingleton(ContextIdApplicationContextInitializer.ContextId.class.getName(), contextId);
}
第四个是ConfigurationWarningsApplicationContextInitializer ,主要是添加了警告后置处理器,检查注解扫描的包是否有问题,如果有,则返回警告:
public void initialize(ConfigurableApplicationContext context) {
context.addBeanFactoryPostProcessor(new ConfigurationWarningsApplicationContextInitializer.ConfigurationWarningsPostProcessor(this.getChecks()));
}
第五个是RSocketPortInfoApplicationContextInitializer ,主要是添加了一个RSocketServerInitializedEvent 事件的监听器到上下文中,可以通过该事件将RSocketServer 服务器实际监听的端口设置到环境属性中。
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addApplicationListener(new RSocketPortInfoApplicationContextInitializer.Listener(applicationContext));
}
第六个是ServerPortInfoApplicationContextInitializer ,它本身也是一个监听器,监听的事件为WebServerInitializedEvent ,可以将端口设置到环境中,然后方便通过@Value 或environment 获取本地端口号。
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addApplicationListener(this);
}
第七个是ConditionEvaluationReportLoggingListener ,也是加了一个监听器,可以打印上下文容器成功刷新或失败的日志报告。
public void initialize(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
applicationContext.addApplicationListener(new ConditionEvaluationReportLoggingListener.ConditionEvaluationReportListener());
if (applicationContext instanceof GenericApplicationContext) {
this.report = ConditionEvaluationReport.get(this.applicationContext.getBeanFactory());
}
}
至此所有初始化器的任务完成了,我们的上下文又多了不少东西,有监听器、ID、后置处理器等。
接着进入到listeners.contextPrepared(context) 方法,调用SpringApplicationRunListeners 监听器,开始进入下一步骤阶段。
和之前应用启动时一样,也响应的创建一个步骤,名称为spring.boot.application.context-prepared (上下文准备完成),然后调用那些监听器中ApplicationPreparedEvent 事件的响应方法,这里就懒得看了,主要有注册springBootLoggingSystem 、springBootLoggerGroups 、打印日志的一些工作。
接着prepareContext 方法又添加了一些后置处理器和加载了一些Bean ,最后进入load 方法,将启动类 BeanDefinition 注册。
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
BeanDefinitionLoader loader = this.createBeanDefinitionLoader(this.getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
loader.load();
}
private void load(Class<?> source) {
if (this.isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
GroovyBeanDefinitionSource loader = (GroovyBeanDefinitionSource)BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
((GroovyBeanDefinitionReader)this.groovyReader).beans(loader.getBeans());
}
if (this.isEligible(source)) {
this.annotatedReader.register(new Class[]{source});
}
}
此时可以看到当前Bean 工厂中,有6个 BeanDefinition。
最后调用listeners.contextLoaded 进行监听器的处理,这里发布的是ApplicationPreparedEvent 事件,可以看到有5个监听器符合,然后就是和之前一样,调用每个监听器的监听方法处理事件,这个阶段好像没做很重要的处理,就不解释了。 处理完成后,prepareContext 这个阶段就完成了,经过创建和准备工作,我们的上下文已经又多了不少东西,接下来就进入刷新方法了。
|