目录
- 5-SpringBoot容器的创建
- 5.1 简介
- 5.2 创建ApplicationContext对象
- 5.2.1 容器工厂创建容器对象
5-SpringBoot容器的创建
5.1 简介
回顾一下我们 前面介绍的SpringBoot应用程序SpringApplication对象的运行方法的生命周期:
先直接贴代码,然后在代码上贴注释来看:
public ConfigurableApplicationContext run(String... args) {
//启动时间
long startTime = System.nanoTime();
//创建启动上下文对象
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
//配置无头属性
configureHeadlessProperty();
//获取运行监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
//调用启动类型的启动方法(这个需要启动类型实现对应接口)
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
//创建应用程序参数对象
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//准备启动环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
//配置需要忽略的Bean信息
configureIgnoreBeanInfo(environment);
//打印一个Banner提示下用户当前版本
Banner printedBanner = printBanner(environment);
//创建应用程序上下文对象
context = createApplicationContext();
//设置下上下文对象的应用程序启动器
context.setApplicationStartup(this.applicationStartup);
//准备上下文
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//刷新上下文
refreshContext(context);
//刷新上下文之后的逻辑
afterRefresh(context, applicationArguments);
//打印启动时间
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
//应用程序启动完成的start回调方法
listeners.started(context, timeTakenToStartup);
//获取所有的ApplicationRunner类型和CommandLineRunner类型对象,
//先调用ApplicationRunner类型的启动方法run
//再调用所有的CommandLineRunner的run方法
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
//失败则转换异常信息打印异常
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
//调用监听器的回调running方法
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
前面我们了解了很多基本信息的初始化比如启动监听器的触发,JVM配置参数,环境变量配置参数,Random配置和应用profile,和应用配置的加载,然后就是给我们打印个Banner信息提示一下SpringBoot的版本号,
接下来就要介绍核心的内容篇幅Spring容器的创建,Spring容器的类型在这里以ConfigurableApplicationContext类型来表示,很多人经常说Spring容器就是ApplicationContext, 为什么会这么说呢那就得看这个类型做了什么可以称为容器.
5.2 创建ApplicationContext对象
这里我们继续看run方法的代码 这里先看创建上下文的具体过程;
SpringApplication类型的createApplicationContext方法
//创建应用程序上下文对象
context = createApplicationContext();
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.create(this.webApplicationType);
}
5.2.1 容器工厂创建容器对象
ApplicationContextFactory 的create方法的实现
这种函数式编程在Java中我还是第一次见 将函数实现赋值给了一个变量这样方法也可以做为一个参数来传递了,也是Java函数编程的一个跨越吧,这个在Erlang中fun函数是一种基本的类型,有了这个实现钩子函数会比较方便
ApplicationContextFactory DEFAULT = (webApplicationType) -> {
try {
//判断当前应用程序类型,根据应用程序类型创建对应的上下文类型
switch (webApplicationType) {
case SERVLET:
return new AnnotationConfigServletWebServerApplicationContext();
case REACTIVE:
return new AnnotationConfigReactiveWebServerApplicationContext();
default:
return new AnnotationConfigApplicationContext();
}
}
catch (Exception ex) {
throw new IllegalStateException("Unable create a default ApplicationContext instance, "
+ "you may need a custom ApplicationContextFactory", ex);
}
};
/**
* Creates the {@link ConfigurableApplicationContext application context} for a
* {@link SpringApplication}, respecting the given {@code webApplicationType}.
* @param webApplicationType the web application type
* @return the newly created application context
*/
ConfigurableApplicationContext create(WebApplicationType webApplicationType);
这里我们需要创建的是AnnotationConfigApplicationContext类型的上下文在了解上下文对象构造器初始化的过程之前,我们先来详细看下上文类型之间的继承关系
从下往上依次解释下每个类型的作用:
- AnnotationConfigApplicationContext
注解配置上下文实现类型
独立应用程序上下文,接受组件类作为输入-特别是@Configuration注解修饰的类,但也包括普通@Component类型以及使用 JSR-330 注释的符合JSR-330的类。
- AnnotationConfigRegistry
配置应用程序上下文的通用接口,定义注册和扫描方法
- GenericApplicationContext
通用上下文实现类型
包含单个内部DefaultListableBeanFactory实例且不采用特定bean定义格式的通用ApplicationContext实现。实现BeanDefinitionRegistry接口,以便允许对其应用任何bean定义读取器。
典型用法是通过BeanDefinitionRegistry接口注册各种bean定义,然后调用refresh() )以使用应用程序上下文语义初始化这些bean(处理org.springframework.context.ApplicationContextAware、自动检测BeanFactoryPostProcessors等)。
与为每次刷新创建新的内部BeanFactory实例的其他ApplicationContext实现不同,此上下文的内部BeanFactory从一开始就可用,可以在其上注册bean定义。refresh() 只能调用一次。
使用方式:
GenericApplicationContext ctx = new GenericApplicationContext();
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
xmlReader.loadBeanDefinitions(new ClassPathResource("applicationContext.xml"));
PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(ctx);
propReader.loadBeanDefinitions(new ClassPathResource("otherBeans.properties"));
ctx.refresh();
MyBean myBean = (MyBean) ctx.getBean("myBean");
对于XML bean定义的典型情况,只需使用ClassPathXmlApplicationContext或FileSystemXmlApplicationContext,它们更容易设置,但灵活性较差,因为您可以只使用XML Bean定义的标准资源位置,而不是混合任意Bean定义格式。在web环境中,等效的是org.springframework.web.context.support.XmlWebApplicationContext.。
对于应该以可刷新的方式读取特殊bean定义格式的自定义应用程序上下文实现,请考虑从AbstractRefreshableApplicationContext基类派生。
查看原文,技术咨询与支持,可以扫描微信公众号进行回复咨询