这篇文章主要介绍“springboot2.0.6中SpringApplication实例初始化”,在日常操作中,相信很多人在springboot2.0.6中SpringApplication实例初始化问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”springboot2.0.6中SpringApplication实例初始化”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { // 设置资源加载器属性 this.resourceLoader = resourceLoader; // 校验主要加载资源不能为空,为空抛出异常 Assert.notNull(primarySources, "PrimarySources must not be null"); // 设置primarySources(主要来源)属性【后面会交给BeanDefinitionLoader,其分别load这些 primarySources 设置到scanner(扫描仪)中,避免重复扫描这些类进入容器】 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); // 获取ApplicationContext类型,并设置到webApplicationType属性中 this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 获取应用上下文初始化器实例集合,并设置到initializers属性中 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); // 获取应用监听器实例集合,并设置到listeners属性中 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 找出main(主入口应用类)类,这里是CoreServerApplication类 this.mainApplicationClass = deduceMainApplicationClass(); }
NONE:既不是运行在 web 容器下的应用并且也不应该启动一个内置的web服务。
SERVLET:是需要运行在基于 servlet 的web应用且需要启动一个内置 servlet-web 服务。
REACTIVE:还是运行在 reactive 的web应用中且需要启动一个 reactive-web 服务。
private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext" }; private static final String WEBMVC_INDICATOR_CLASS = "org.springframework." + "web.servlet.DispatcherServlet"; private static final String WEBFLUX_INDICATOR_CLASS = "org." + "springframework.web.reactive.DispatcherHandler"; private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer"; private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext"; private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext"; static WebApplicationType deduceFromClasspath() { if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { return WebApplicationType.REACTIVE; } for (String className : SERVLET_INDICATOR_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; } } return WebApplicationType.SERVLET; }
根据org.springframework.util.ClassUtils的静态方法 isPresent 判断classpath里面是否有包含 WEBFLUX_INDICATOR_CLASS 并且没有包含 WEBMVC_INDICATOR_CLASS 和 JERSEY_INDICATOR_CLASSERVLET_INDICATOR_CLASSE ,满足条件则表示启动一个 REACTIVE 类型的WEB应用,不满足上述条件且有 SERVLET_INDICATOR_CLASSES 包含的类,则表示启动一个 SERVLET 类型的WEB应用,否则启动一个标准应用。
是否启动一个WEB应用就是取决于 classpath 下是否满足有 javax.servlet.Servlet 和 org.springframework.web.context.ConfigurableWebApplicationContext 或有 org. springframework.web.reactive.DispatcherHandler 并且没有org.springframework.web.servlet.DispatcherServlet 和 org.glassfish.jersey.servlet.ServletContainer。
初始化 classpath 下的所有的可用的 ApplicationContextInitializer
ApplicationContextInitializer 应用程序初始化器,做一些初始化的工作,是 springboot 准备调用 prepareContext 方法准备 spring 容器(此时spring容器已经创建需要refresh)之前调用的用来在这个时间点执行一些操作:比如设置 servletContext 等
默认情况下,getSpringFActoriesInstances 方法从 spring.factories 文件中找出key为 ApplicationContextInitializer 类型的权限定名称集合有:
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer:
向应用上下文中注册后置处理器(ConfigurationWarningsPostProcessor)
org.springframework.boot.context.ContextIdApplicationContextInitializer
设置应用上下文ID,并将上面生成的ContextId(ContextIdApplicationContextInitializer)对象,作为一个单例bean注册到当前应用上下文。
org.springframework.boot.context.config.DelegatingApplicationContextInitializer
执行环境属性"context.initializer.classes"指定的初始化器,然后执行这些初始化器。这里实现springboot应用程序自己实现的ApplicationContextInitializer对应用程序做一些初始化工作。
org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer
把自己作为监听器注册到应用上下文中
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer
向应用上下文中注册后置处理器(CachingMetadataReaderFactoryPostProcessor)
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
向应用上下文中注册监听器(ConditionEvaluationReportListener)当应用上下文实现GenercApplicationContext时,则设置“report”属性
( 图1-2 spring-boot.jar 中 spring.factories文件中applicationContextInitializer相关)
( 图1 执行getSpringFactoriesInstances(ApplicationContextInitializer.class)获取 spring.factories文件中applicationContextInitializer相关的工厂类,并进行初始化)
( 图2 springApplication对象中instances属性值)
初使化 classpath 下的所有的可用的 ApplicationListener
ApplicationListener 应用程序事件(ApplicationEvent)监听器
这里的应用程序事件(ApplicationEvent)有应用程序启动事件(ApplicationStartedEvent),失败事件(ApplicationFailedEvent),准备事件(ApplicationPreparedEvent)等
应用程序事件监听器跟监听事件是绑定的。比如 ConfigServerBootstrapApplicationListener 只跟 ApplicationEnvironmentPreparedEvent 事件绑定, LiquibaseServiceLocatorApplicationListener 只跟 ApplicationStartedEvent 事件绑定,LoggingApplicationListener 跟所有事件绑定等
默认情况下,getSpringFactoriesInstances 方法从 spring.factories 文件中找出key为 ApplicationListener 类型的,类全限定名称集合有:
org.springframework.boot.autoconfigure.BackgroundPreinitializer
org.springframework.boot.ClearCachesApplicationListener
org.springframework.boot.builder.ParentContextCloserApplicationListener
org.springframework.boot.context.FileEncodingApplicationListener
org.springframework.boot.context.config.AnsiOutputApplicationListener
org.springframework.boot.context.config.ConfigFileApplicationListener
org.springframework.boot.context.config.DelegatingApplicationListener
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener
org.springframework.boot.context.logging.LoggingApplicationListener
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
( 图3-1 spring-boot.jar 中 spring.factories文件中applicationlistener相关)
( 图3-2 spring-boot.jar 中 spring.factories文件中applicationlistener相关)
( 图4 执行getSpringFactoriesInstances(Applicationlistener.class)获取 spring.factories文件中applicationContextInitializer相关的工厂类,并进行初始化)
由于spring 有一大堆事件比如 ContextRefreshedEvent,ContextStartedEvent 等等 我们有一个 ApplicationListener 就会监听到这些事件进而做相应的处理。
其实都是 applicationContext 调用其 publishEvent 发送一些 event,该方法会从很多 listener 中找到对该 event 感兴趣的 listener 调用其 onApplicationEvent,而实现这些的就是 SimpleApplicationEventMulticaster,如果有 Executor,其会优先使用Executor来执行这就可能导致我们的回调是异步的。
applicationContext 还会把event传播到其父容器(我们知道我们常用到AnnotationConfigApplicationContext 已经其有很多父容器)
这边还有一个策略就是如果 earlyApplicationEvents 存在 则先把事件加入到 earlyApplicationEvents,稍后在发送,如果不存在则直接发送。
applicationevent 中包含时间戳,springboot 启动类(source),还有我们的spring容器
如果我们想自己在代码中写 ApplicationContextInitializer 和 ApplicationListener 的实现类时候可以采用下列方式:
在项目中建立一个 META-INF/spring.factories 文件,里面以 key=value 存放我们的实现类
手动调用 SpringApplication 的对应添加方法也可以
在我们的 application.properties 里面配置 context.initializer.classes = 实现类(通过 DelegatingApplicationContextInitializer 获取到我们配置的 initializer,进而可以保证在 prepareContext 时候调用),context.listener.classes = 实现类(无法监听到 springboot 启动时候的一些事件,因为那个时候该实现类还未加入容器)
虽然我们使用 @Configuration 来讲我们 ApplicationListener 的实现类加入到spring容器,且也能监听到程序正常运行的一些事件(无法监听到 springboot 启动时候的一些事件,因为那个时候该实现类还未加入容器),但是 我们如果想监听全部的事件最好使用上述三种方式配置这样可以在 springboot 启动的时候就监听
通过系统加载类去指定目录下根据 propties 文件获取对应的 class 的全限定名称
SpringApplication 的构造方法主要就是设置 Initializers 和 Listeners 同时设置 primaryClass 方便后面先去加载 primaryClass,而且也顺便确定了当前的 springboot 的运行环境
到此,关于“springboot2.0.6中SpringApplication实例初始化”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。