日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

Springboot源码——应用程序上下文分析

發布時間:2025/3/8 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Springboot源码——应用程序上下文分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  前兩篇(Spring MVC源碼——Root WebApplicationContext?和 Spring MVC源碼——Servlet WebApplicationContext)講述了springmvc項目創建上下文的過程,這一篇帶大家了解一下springboot項目創建上下文的過程。

SpringApplication引導類

SpringApplication類用于啟動或者引導springboot項目,直接應用在java main方法中。

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));//判斷當前web應用程序類型this.webApplicationType = deduceWebApplicationType();//找到*META-INF/spring.factories*中聲明的所有ApplicationContextInitializer的實現類并將其實例化 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));//找到*META-INF/spring.factories*中聲明的所有ApplicationListener的實現類并將其實例化setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));//獲得當前執行main方法的類對象this.mainApplicationClass = deduceMainApplicationClass(); }

springboot項目WebApplicationType分為三種:非web類型,web類型(spring-mvc),響應式web類型(spring-webflux)

private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext" };private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework."+ "web.reactive.DispatcherHandler";private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework."+ "web.servlet.DispatcherServlet";private WebApplicationType deduceWebApplicationType() {if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {return WebApplicationType.REACTIVE;}for (String className : WEB_ENVIRONMENT_CLASSES) {if (!ClassUtils.isPresent(className, null)) {return WebApplicationType.NONE;}}return WebApplicationType.SERVLET; }

下面的run方法是springboot項目啟動的核心代碼。

public ConfigurableApplicationContext run(String... args) {//開啟任務執行時間監聽器StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();//設置系統屬性『java.awt.headless』,為true則啟用headless模式支持 configureHeadlessProperty();//通過*SpringFactoriesLoader*檢索*META-INF/spring.factories*,//找到聲明的所有SpringApplicationRunListener的實現類并將其實例化,//之后逐個調用其started()方法,廣播SpringBoot要開始執行了。SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting();try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//創建并配置當前SpringBoot應用將要使用的Environment(包括配置要使用的PropertySource以及Profile),//并遍歷調用所有的SpringApplicationRunListener的environmentPrepared()方法,廣播Environment準備完畢。 ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);//是否搜索BeanInfo類 configureIgnoreBeanInfo(environment);//Banner打印Banner printedBanner = printBanner(environment);//根據WebApplicationType的值來決定創建何種類型的ApplicationContext對象context = createApplicationContext();//通過*SpringFactoriesLoader*檢索*META-INF/spring.factories*,獲取并實例化異常分析器exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);//為ApplicationContext加載environment,之后逐個執行ApplicationContextInitializer的initialize()方法來進一步封裝ApplicationContext,//并調用所有的SpringApplicationRunListener的contextPrepared()方法,【EventPublishingRunListener只提供了一個空的contextPrepared()方法】,//之后初始化IoC容器,并調用SpringApplicationRunListener的contextLoaded()方法,廣播ApplicationContext的IoC加載完成,//這里就包括通過**@EnableAutoConfiguration**導入的各種自動配置類。 prepareContext(context, environment, listeners, applicationArguments,printedBanner);//初始化所有自動配置類,調用ApplicationContext的refresh()方法 refreshContext(context);//空方法 afterRefresh(context, applicationArguments);/關閉任務執行時間監聽器stopWatch.stop();//如果開啟日志,則打印執行是時間if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}//調用所有的SpringApplicationRunListener的started()方法,廣播SpringBoot已經完成了ApplicationContext初始化的全部過程。 listeners.started(context);//遍歷所有注冊的ApplicationRunner和CommandLineRunner,并執行其run()方法。//我們可以實現自己的ApplicationRunner或者CommandLineRunner,來對SpringBoot的啟動過程進行擴展。 callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}try {//調用所有的SpringApplicationRunListener的running()方法,廣播SpringBoot已經可以處理服務請求了。 listeners.running(context);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}return context; }

由上文可知,默認WebApplicationType是WebApplicationType.SERVLET,所以默認的上下文是AnnotationConfigServletWebServerApplicationContext。

//應用程序非web環境 public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."+ "annotation.AnnotationConfigApplicationContext";//應用程序web環境 public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework.boot."+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";//應用程序響應式web環境 public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";public enum WebApplicationType {//應用程序不需要任何應用服務器 NONE,//應用程序內嵌web服務器 SERVLET,//應用程序內嵌響應式web服務器 REACTIVE}protected ConfigurableApplicationContext createApplicationContext() {Class<?> contextClass = this.applicationContextClass;if (contextClass == null) {try {switch (this.webApplicationType) {case SERVLET:contextClass = Class.forName(DEFAULT_WEB_CONTEXT_CLASS);break;case REACTIVE:contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);break;default:contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);}}catch (ClassNotFoundException ex) {throw new IllegalStateException("Unable create a default ApplicationContext, "+ "please specify an ApplicationContextClass",ex);}}return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass); }

AnnotationConfigServletWebServerApplicationContext類結構層次如下。

父類ServletWebServerApplicationContext創建內嵌web應用服務器如下。

@Override protected void onRefresh() {super.onRefresh();try {//創建web應用服務 createWebServer();}catch (Throwable ex) {throw new ApplicationContextException("Unable to start web server", ex);} }private void createWebServer() {WebServer webServer = this.webServer;ServletContext servletContext = getServletContext();if (webServer == null && servletContext == null) {//獲取ServletWebServerFactory類型的web服務器工廠類,比如TomcatServletWebServerFactory,JettyServletWebServerFactory,UndertowServletWebServerFactoryServletWebServerFactory factory = getWebServerFactory();this.webServer = factory.getWebServer(getSelfInitializer());}else if (servletContext != null) {try {getSelfInitializer().onStartup(servletContext);}catch (ServletException ex) {throw new ApplicationContextException("Cannot initialize servlet context",ex);}}initPropertySources(); }

Springmvc項目上下文和Springboot項目上下文淺析

Springmvc項目上下文

Springmvc項目的rootcontext的創建時通過 xml中 配置的org.springframework.web.context.ContextLoaderListener,其父類ContextLoader中有一個初始化上下文的方法,如下。 public WebApplicationContext initWebApplicationContext(ServletContext servletContext);

上下文創建好之后調用

servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

其中 servletContext的實例是 org.apache.catalina.core.ApplicationContext;

WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = org.springframework.web.context.WebApplicationContext.ROOT)

這樣rootcontext就創建好了,并且放入了servletContext中保存。rootcontext獲取方式如下。?

WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());

Springmvc項目中的DispatcherServlet是在xml中按照servlet格式配置的,這種方式創建的servlet實例沒有被spring容器管理。

DispatcherServlet實現了ApplicationContextAware接口,有一個成員變量來保存此servlet對應的上下文,如下。 /** WebApplicationContext for this servlet */ private WebApplicationContext webApplicationContext;

這種情況下webApplicationContext變量是無法注入的【DispatcherServlet實例沒有被spring容器管理】。看一下DispatcherServlet的父類FrameworkServlet是如何初始化上下文的,如下。

protected WebApplicationContext initWebApplicationContext() {WebApplicationContext rootContext =WebApplicationContextUtils.getWebApplicationContext(getServletContext());WebApplicationContext wac = null; //springmvc項目這塊的判斷為false;springboot項目為ture。if (this.webApplicationContext != null) {......

DispatcherServlet所屬上下文的存儲

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {...request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());... }

DispatcherServlet所屬上下文獲取org.springframework.web.servlet.support.RequestContextUtils。

Springboot項目上下文

Springboot項目中,調試代碼時發現DispatcherServlet的父類FrameworkServlet在初始化上下文的時候rootcontext 和?DispatcherServlet成員變量webApplicationContext保存的是一個實例,即AnnotationConfigServletWebServerApplicationContext實例。 上面也提到了DispatcherServlet【對應的實例被spring容器管理】實現了ApplicationContextAware接口,webApplicationContext保存的上下文是通過自動注入而來。 RootContext(AnnotationConfigServletWebServerApplicationContext)保存到servletcontext中的操作,如下。 //ServletWebServerApplicationContext
protected
void prepareWebApplicationContext(ServletContext servletContext) {...servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this);... }

總結

經過三篇文章的分析,相信大家已經明白了Springmvc項目默認是有兩個上下文(Root webapplicationcontext 和 Servlet webapplicationcontext,對應的類型是XmlServletWebServerApplicationContext),而Springboot項目默認是一個上下文,對應的類型是AnnotationConfigServletWebServerApplicationContext。如果有什么疑問,請關注訂閱號,進行私聊。

轉載于:https://www.cnblogs.com/hujunzheng/p/10854464.html

總結

以上是生活随笔為你收集整理的Springboot源码——应用程序上下文分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。