上一篇文章介绍了springboot的异常上报,这里接着就是应用上下文准备
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
注意,run方法中,前面已经创建了运行环境(createApplicationContext)所以
第一个参数就是前面创建的运行环境的context,
第二个是运行环境environment
第三个是listeners 当然,还是只有SpringApplicationRunListeners 这一个
第四个是参数类,目前没有参数。
第五个是打印banner的。
代码如下
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
1.设置上下文环境
context.setEnvironment(environment);
其实也只是把环境赋值过去
@Override
public void setEnvironment(ConfigurableEnvironment environment) {
super.setEnvironment(environment);
this.reader.setEnvironment(environment);
this.scanner.setEnvironment(environment);
}
2.ApplicationContext的后置处理
设置ApplicationContext的beanNameGenerator
设置ApplicationContext的resourceLoader和classLoader
设置ApplicationContext的类型转换Service
/**
* Apply any relevant post processing the {@link ApplicationContext}. Subclasses can
* apply additional processing as required.
* @param context the application context
*/
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
if (this.beanNameGenerator != null) {
context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
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(ApplicationConversionService.getSharedInstance());
}
}
3.应用初始化
applyInitializers(context);
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
这里的初始化器有7个。
其实就是在spring.facotories中定义的
#Initializers
org.springframework.context.Applicatinotallow=
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
#Application Context Initializers
org.springframework.context.Applicatinotallow=
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,
org.springframework.boot.context.ContextIdApplicationContextInitializer,
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
分别进入到
1.SharedMetadataReaderFactoryContextInitializer.initialize()函数
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addBeanFactoryPostProcessor(new CachingMetadataReaderFactoryPostProcessor());
}
2.DelegatingApplicationContextInitializer.initialize函数
public void initialize(ConfigurableApplicationContext context) {
ConfigurableEnvironment environment = context.getEnvironment();
List<Class<?>> initializerClasses = getInitializerClasses(environment);
if (!initializerClasses.isEmpty()) {
applyInitializerClasses(context, initializerClasses);
}
}
3.ContextIdApplicationContextInitializer.initialize函数
public void initialize(ConfigurableApplicationContext applicationContext) {
ContextId contextId = getContextId(applicationContext);
applicationContext.setId(contextId.getId());
applicationContext.getBeanFactory().registerSingleton(ContextId.class.getName(), contextId);
}
4.ConditionEvaluationReportLoggingListener.initialize函数
public void initialize(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
applicationContext.addApplicationListener(new ConditionEvaluationReportListener());
if (applicationContext instanceof GenericApplicationContext) {
// Get the report early in case the context fails to load
this.report = ConditionEvaluationReport.get(this.applicationContext.getBeanFactory());
}
}
5.ConfigurationWarningsApplicationContextInitializer.initialize函数
public void initialize(ConfigurableApplicationContext context) {
context.addBeanFactoryPostProcessor(new ConfigurationWarningsPostProcessor(getChecks()));
}
6.RSocketPortInfoApplicationContextInitializer.initialize函数
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addApplicationListener(new Listener(applicationContext));
}
7.ServerPortInfoApplicationContextInitializer.initialize函数
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addApplicationListener(this);
}
4.监听器发布事件(ApplicationContextInitializedEvent)
listeners.contextPrepared(context);
一路执行到
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClass());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
Application容器初始化完成事件, 对该事件感兴趣的监听器有
BackgroundPreinitializer
@Override
public void onApplicationEvent(SpringApplicationEvent event) {
if (!Boolean.getBoolean(IGNORE_BACKGROUNDPREINITIALIZER_PROPERTY_NAME)
&& event instanceof ApplicationStartingEvent && multipleProcessors()
&& preinitializationStarted.compareAndSet(false, true)) {
performPreinitialization();
}
if ((event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent)
&& preinitializationStarted.get()) {
try {
preinitializationComplete.await();
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
DelegatingApplicationListener
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
List<ApplicationListener<ApplicationEvent>> delegates = getListeners(
((ApplicationEnvironmentPreparedEvent) event).getEnvironment());
if (delegates.isEmpty()) {
return;
}
this.multicaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<ApplicationEvent> listener : delegates) {
this.multicaster.addApplicationListener(listener);
}
}
if (this.multicaster != null) {
this.multicaster.multicastEvent(event);
}
}
5.打印启动和profile日志
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
void logStarting(Log applicationLog) {
Assert.notNull(applicationLog, "Log must not be null");
applicationLog.info(LogMessage.of(this::getStartingMessage));
applicationLog.debug(LogMessage.of(this::getRunningMessage));
}
public void info(Object message) {
if (message instanceof String || this.logger.isInfoEnabled()) {
this.logger.log(null, FQCN, LocationAwareLogger.INFO_INT, String.valueOf(message), null, null);
}
}
public void log(Marker marker, String fqcn, int levelInt, String message, Object[] argArray, Throwable t) {
Level level = Level.fromLocationAwareLoggerInteger(levelInt);
filterAndLog_0_Or3Plus(fqcn, marker, level, message, argArray, t);
}
通过fromLocationAwareLoggerInteger函数确定当前应用的log日志级别
public static Level fromLocationAwareLoggerInteger(int levelInt) {
Level level;
switch (levelInt) {
case LocationAwareLogger.TRACE_INT:
level = TRACE;
break;
case LocationAwareLogger.DEBUG_INT:
level = DEBUG;
break;
case LocationAwareLogger.INFO_INT:
level = INFO;
break;
case LocationAwareLogger.WARN_INT:
level = WARN;
break;
case LocationAwareLogger.ERROR_INT:
level = ERROR;
break;
default:
throw new IllegalArgumentException(levelInt + " not a valid level value");
}
return level;
}
最终在这里执行了输出
/Users/yyrj/.gradle/caches/modules-2/files-2.1/ch.qos.logback/logback-core/1.2.3/3ebabe69eba0196af9ad3a814f723fb720b9101e/logback-core-1.2.3-sources.jar!/ch/qos/logback/core/OutputStreamAppender.java
private void writeBytes(byte[] byteArray) throws IOException {
if(byteArray == null || byteArray.length == 0)
return;
lock.lock();
try {
this.outputStream.write(byteArray);
if (immediateFlush) {
this.outputStream.flush();
}
} finally {
lock.unlock();
}
}
logStartupProfileInfo函数输出当前活跃的配置
protected void logStartupProfileInfo(ConfigurableApplicationContext context) {
Log log = getApplicationLog();
if (log.isInfoEnabled()) {
String[] activeProfiles = context.getEnvironment().getActiveProfiles();
if (ObjectUtils.isEmpty(activeProfiles)) {
String[] defaultProfiles = context.getEnvironment().getDefaultProfiles();
log.info("No active profile set, falling back to default profiles: "
+ StringUtils.arrayToCommaDelimitedString(defaultProfiles));
}
else {
log.info("The following profiles are active: "
+ StringUtils.arrayToCommaDelimitedString(activeProfiles));
}
}
}
在控制台输出的内容
2020-01-10 20:31:27.832 INFO 26086 — [ main] com.example.demo.DemoApplication : The following profiles are active: test
6 注册单例Bean
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
注意注册进去的单例有4个。其中有两个就是这里注册进去的。
允许bean定义重写。
/**
* Set whether it should be allowed to override bean definitions by registering
* a different definition with the same name, automatically replacing the former.
* If not, an exception will be thrown. This also applies to overriding aliases.
* <p>Default is "true".
* @see #registerBeanDefinition
*/
public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) {
this.allowBeanDefinitionOverriding = allowBeanDefinitionOverriding;
}
7.懒加载
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
8.load加载
创建了一个BeanDefinitionLoader对象;BeanDefinitionLoader作为AnnotatedBeanDefinitionReader,XmlBeanDefinitionReader和ClassPathBeanDefinitionScanner的门面,从底层源加载bean定义,包括XML和JavaConfig;
能被加载的source类型包括:Class、Resource、Package和CharSequence四种,每种类型的加载方式也不一样,Class用AnnotatedBeanDefinitionReader处理、Resource用XmlBeanDefinitionReader处理、Package用ClassPathBeanDefinitionScanner,而CharSequence则比较特殊了,它按Class、Resource、Package的顺序处理,哪种处理成功就按哪种处理(CharSequence方式貌似很少用,反正我还没用过);
而目前我们的source只有一个:class com.lee.shiro.ShiroApplication,是class类型;先判断ShiroApplication是否有被component注解修饰,很显然是(SpringBootApplication注解中包含component注解),那么AnnotatedBeanDefinitionReader来处理:将com.lee.shiro.ShiroApplication封装成一个名叫ShiroApplication的BeanDefinition对象,并将其注册到了beanFactory的BeanDefinitionMap中。
9.发布contextLoaded事件
listeners.contextLoaded(context);
发布 org.springframework.boot.context.event.ApplicationPreparedEvent 类型4个listener对该事件感兴趣。
ConfigFileApplicationListener
LoggingApplicationListener
BackgroundPreinitializer
DelegatingApplicationListener
prepareContext函数到这里结束。
2020年01月10日
witch_soya