日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

spring boot中servlet启动原理

發(fā)布時(shí)間:2023/12/9 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spring boot中servlet启动原理 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

啟動(dòng)過程及原理

1 spring boot 應(yīng)用啟動(dòng)運(yùn)行run方法

StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;FailureAnalyzers analyzers = null;configureHeadlessProperty();SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting();try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);Banner printedBanner = printBanner(environment);//創(chuàng)建一個(gè)ApplicationContext容器context = createApplicationContext();analyzers = new FailureAnalyzers(context);prepareContext(context, environment, listeners, applicationArguments,printedBanner);//刷新IOC容器 refreshContext(context);afterRefresh(context, applicationArguments);listeners.finished(context, null);stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}return context;}catch (Throwable ex) {handleRunFailure(context, listeners, analyzers, ex);throw new IllegalStateException(ex);}

?

2? createApplicationContext():創(chuàng)建IOC容器,如果是web應(yīng)用則創(chuàng)建AnnotationConfigEmbeddedWebApplacation的IOC容器,如果不是,則創(chuàng)建AnnotationConfigApplication的IOC容器

public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."+ "annotation.AnnotationConfigApplicationContext";/*** The class name of application context that will be used by default for web* environments.*/public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework."+ "boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext";protected ConfigurableApplicationContext createApplicationContext() {Class<?> contextClass = this.applicationContextClass;if (contextClass == null) {try {
          //根據(jù)應(yīng)用環(huán)境,創(chuàng)建不同的IOC容器contextClass
= Class.forName(this.webEnvironment? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);}catch (ClassNotFoundException ex) {throw new IllegalStateException("Unable create a default ApplicationContext, "+ "please specify an ApplicationContextClass",ex);}}return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);}

3? ? refreshContext(context) spring boot刷新IOC容器(創(chuàng)建容器對象,并初始化容器,創(chuàng)建容器每一個(gè)組件)

private void refreshContext(ConfigurableApplicationContext context) {refresh(context);if (this.registerShutdownHook) {try {context.registerShutdownHook();}catch (AccessControlException ex) {// Not allowed in some environments. }}}

4 refresh(context);刷新剛才創(chuàng)建的IOC容器

protected void refresh(ApplicationContext applicationContext) {Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);((AbstractApplicationContext) applicationContext).refresh();}

5 調(diào)用父類的refresh()的方法

public void refresh() throws BeansException, IllegalStateException {Object var1 = this.startupShutdownMonitor;synchronized(this.startupShutdownMonitor) {this.prepareRefresh();ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();this.prepareBeanFactory(beanFactory);try {this.postProcessBeanFactory(beanFactory);this.invokeBeanFactoryPostProcessors(beanFactory);this.registerBeanPostProcessors(beanFactory);this.initMessageSource();this.initApplicationEventMulticaster();this.onRefresh();this.registerListeners();this.finishBeanFactoryInitialization(beanFactory);this.finishRefresh();} catch (BeansException var9) {if (this.logger.isWarnEnabled()) {this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);}this.destroyBeans();this.cancelRefresh(var9);throw var9;} finally {this.resetCommonCaches();}}}

6? 抽象父類AbstractApplicationContext類的子類EmbeddedWebApplicationContext的onRefresh方法

@Overrideprotected void onRefresh() {super.onRefresh();try {createEmbeddedServletContainer();}catch (Throwable ex) {throw new ApplicationContextException("Unable to start embedded container",ex);}}

7? 在createEmbeddedServletContainer放啊發(fā)中會(huì)獲取嵌入式Servlet容器工廠,由容器工廠創(chuàng)建Servlet

private void createEmbeddedServletContainer() {EmbeddedServletContainer localContainer = this.embeddedServletContainer;ServletContext localServletContext = getServletContext();if (localContainer == null && localServletContext == null) {
                //獲取嵌入式Servlet容器工廠EmbeddedServletContainerFactory containerFactory
= getEmbeddedServletContainerFactory();
          //根據(jù)容器工廠獲取對應(yīng)嵌入式Servlet容器
this.embeddedServletContainer = containerFactory.getEmbeddedServletContainer(getSelfInitializer());}else if (localServletContext != null) {try {getSelfInitializer().onStartup(localServletContext);}catch (ServletException ex) {throw new ApplicationContextException("Cannot initialize servlet context",ex);}}initPropertySources();}

8? 從IOC容器中獲取Servlet容器工廠

//EmbeddedWebApplicationContext#getEmbeddedServletContainerFactory protected EmbeddedServletContainerFactory getEmbeddedServletContainerFactory() { // Use bean names so that we don't consider the hierarchy String[] beanNames = getBeanFactory() .getBeanNamesForType(EmbeddedServletContainerFactory.class); if (beanNames.length == 0) { throw new ApplicationContextException( "Unable to start EmbeddedWebApplicationContext due to missing " + "EmbeddedServletContainerFactory bean."); } if (beanNames.length > 1) { throw new ApplicationContextException( "Unable to start EmbeddedWebApplicationContext due to multiple " + "EmbeddedServletContainerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames)); } return getBeanFactory().getBean(beanNames[0], EmbeddedServletContainerFactory.class); }

?

9? 使用Servlet容器工廠獲取嵌入式Servlet容器,具體使用哪一個(gè)容器工廠看配置環(huán)境依賴

this.embeddedServletContainer = containerFactory .getEmbeddedServletContainer(getSelfInitializer());

10? 上述創(chuàng)建過程? 首先啟動(dòng)IOC容器,接著啟動(dòng)嵌入式Servlet容器,接著將IOC容器中剩下沒有創(chuàng)建的對象獲取出來,比如自己創(chuàng)建的controller

// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory); protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {// Initialize conversion service for this context.if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));}// Register a default embedded value resolver if no bean post-processor// (such as a PropertyPlaceholderConfigurer bean) registered any before:// at this point, primarily for resolution in annotation attribute values.if (!beanFactory.hasEmbeddedValueResolver()) {beanFactory.addEmbeddedValueResolver(new StringValueResolver() {@Overridepublic String resolveStringValue(String strVal) {return getEnvironment().resolvePlaceholders(strVal);}});}// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);for (String weaverAwareName : weaverAwareNames) {getBean(weaverAwareName);}// Stop using the temporary ClassLoader for type matching.beanFactory.setTempClassLoader(null);// Allow for caching all bean definition metadata, not expecting further changes. beanFactory.freezeConfiguration();// Instantiate all remaining (non-lazy-init) singletons. beanFactory.preInstantiateSingletons();}

?

看看?preInstantiateSingletons方法

public void preInstantiateSingletons() throws BeansException {if (this.logger.isDebugEnabled()) {this.logger.debug("Pre-instantiating singletons in " + this);}List<String> beanNames = new ArrayList(this.beanDefinitionNames);Iterator var2 = beanNames.iterator();while(true) {while(true) {String beanName;RootBeanDefinition bd;do {do {do {if (!var2.hasNext()) {var2 = beanNames.iterator();while(var2.hasNext()) {beanName = (String)var2.next();Object singletonInstance = this.getSingleton(beanName);if (singletonInstance instanceof SmartInitializingSingleton) {final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton)singletonInstance;if (System.getSecurityManager() != null) {AccessController.doPrivileged(new PrivilegedAction<Object>() {public Object run() {smartSingleton.afterSingletonsInstantiated();return null;}}, this.getAccessControlContext());} else {smartSingleton.afterSingletonsInstantiated();}}}return;}beanName = (String)var2.next();bd = this.getMergedLocalBeanDefinition(beanName);} while(bd.isAbstract());} while(!bd.isSingleton());} while(bd.isLazyInit());if (this.isFactoryBean(beanName)) {final FactoryBean<?> factory = (FactoryBean)this.getBean("&" + beanName);boolean isEagerInit;if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {isEagerInit = ((Boolean)AccessController.doPrivileged(new PrivilegedAction<Boolean>() {public Boolean run() {return ((SmartFactoryBean)factory).isEagerInit();}}, this.getAccessControlContext())).booleanValue();} else {isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean)factory).isEagerInit();}if (isEagerInit) {this.getBean(beanName);}} else {
            //注冊bean
this.getBean(beanName);}}}}

是使用getBean方法來通過反射將所有未創(chuàng)建的實(shí)例創(chuàng)建出來

??使用嵌入式Servlet容器:

?    優(yōu)點(diǎn):? ?簡單,便攜

     缺點(diǎn):? ?默認(rèn)不支持jsp,優(yōu)化定制比較復(fù)雜

使用外置Servlet容器的步驟:

  1? 必須創(chuàng)建war項(xiàng)目,需要?jiǎng)纖eb項(xiàng)目的目錄結(jié)構(gòu)

  2? 嵌入式Tomcat依賴scope指定provided

  3? 編寫SpringBootServletInitializer類子類,并重寫configure方法

public class ServletInitializer extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(SpringBoot04WebJspApplication.class); } }

?

? ? ? ?4? 啟動(dòng)服務(wù)器

jar包和war包啟動(dòng)區(qū)別

? ? jar包:執(zhí)行SpringBootApplication的run方法,啟動(dòng)IOC容器,然后創(chuàng)建嵌入式Servlet容器

 war包:? 先是啟動(dòng)Servlet服務(wù)器,服務(wù)器啟動(dòng)Springboot應(yīng)用(springBootServletInitizer),然后啟動(dòng)IOC容器

Servlet 3.0+規(guī)則

  ? 1? 服務(wù)器啟動(dòng)(web應(yīng)用啟動(dòng)),會(huì)創(chuàng)建當(dāng)前web應(yīng)用里面所有jar包里面的ServletContainerlnitializer實(shí)例

  ? ?2?ServletContainerInitializer的實(shí)現(xiàn)放在jar包的META-INF/services文件夾下

   3? 還可以使用@HandlesTypes注解,在應(yīng)用啟動(dòng)的時(shí)候加載指定的類。

外部Tomcat流程以及原理

  ①? 啟動(dòng)Tomcat

  ②??根據(jù)上述描述的Servlet3.0+規(guī)則,可以在Spring的web模塊里面找到有個(gè)文件名為javax.servlet.ServletContainerInitializer的文件,而文件的內(nèi)容為org.springframework.web.SpringServletContainerInitializer,用于加載SpringServletContainerInitializer類

  ③看看SpringServletContainerInitializer定義

@HandlesTypes(WebApplicationInitializer.class) public class SpringServletContainerInitializer implements ServletContainerInitializer {/*** Delegate the {@code ServletContext} to any {@link WebApplicationInitializer}* implementations present on the application classpath.* <p>Because this class declares @{@code HandlesTypes(WebApplicationInitializer.class)},* Servlet 3.0+ containers will automatically scan the classpath for implementations* of Spring's {@code WebApplicationInitializer} interface and provide the set of all* such types to the {@code webAppInitializerClasses} parameter of this method.* <p>If no {@code WebApplicationInitializer} implementations are found on the classpath,* this method is effectively a no-op. An INFO-level log message will be issued notifying* the user that the {@code ServletContainerInitializer} has indeed been invoked but that* no {@code WebApplicationInitializer} implementations were found.* <p>Assuming that one or more {@code WebApplicationInitializer} types are detected,* they will be instantiated (and <em>sorted</em> if the @{@link* org.springframework.core.annotation.Order @Order} annotation is present or* the {@link org.springframework.core.Ordered Ordered} interface has been* implemented). Then the {@link WebApplicationInitializer#onStartup(ServletContext)}* method will be invoked on each instance, delegating the {@code ServletContext} such* that each instance may register and configure servlets such as Spring's* {@code DispatcherServlet}, listeners such as Spring's {@code ContextLoaderListener},* or any other Servlet API componentry such as filters.* @param webAppInitializerClasses all implementations of* {@link WebApplicationInitializer} found on the application classpath* @param servletContext the servlet context to be initialized* @see WebApplicationInitializer#onStartup(ServletContext)* @see AnnotationAwareOrderComparator*/@Overridepublic void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)throws ServletException {List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();if (webAppInitializerClasses != null) {for (Class<?> waiClass : webAppInitializerClasses) {// Be defensive: Some servlet containers provide us with invalid classes,// no matter what @HandlesTypes says...if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&WebApplicationInitializer.class.isAssignableFrom(waiClass)) {try {
                //為所有的WebApplicationInitializer類型創(chuàng)建實(shí)例,并加入集合中initializers.add((WebApplicationInitializer) waiClass.newInstance());}
catch (Throwable ex) {throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);}}}}if (initializers.isEmpty()) {servletContext.log("No Spring WebApplicationInitializer types detected on classpath");return;}servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");AnnotationAwareOrderComparator.sort(initializers);
      //調(diào)用每一個(gè)WebApplicationInitializer實(shí)例的onstartup方法
for (WebApplicationInitializer initializer : initializers) {initializer.onStartup(servletContext);}}}

?在上面一段長長的注釋中可以看到,SpringServletContainerInitializer將@HandlesTypes(WebApplicationInitializer.class)標(biāo)注的所有WebApplicationInitializer這個(gè)類型的類都傳入到onStartup方法的Set參數(shù)中,并通過反射為這些WebApplicationInitializer類型的類創(chuàng)建實(shí)例;

  ④? 方法最后,每一個(gè)WebApplicationInitilizer實(shí)現(xiàn)調(diào)用自己onstartup方法

  ⑤??而WebApplicationInitializer有個(gè)抽象實(shí)現(xiàn)類SpringBootServletInitializer(記住我們繼承了該抽象類),則會(huì)調(diào)用每一個(gè)WebApplicationInitializer實(shí)例(包括SpringBootServletInitializer)的onStartup方法:

public abstract class SpringBootServletInitializer implements WebApplicationInitializer { //other code... @Override public void onStartup(ServletContext servletContext) throws ServletException { // Logger initialization is deferred in case a ordered // LogServletContextInitializer is being used this.logger = LogFactory.getLog(getClass()); //創(chuàng)建IOC容器 WebApplicationContext rootAppContext = createRootApplicationContext( servletContext); if (rootAppContext != null) { servletContext.addListener(new ContextLoaderListener(rootAppContext) { @Override public void contextInitialized(ServletContextEvent event) { // no-op because the application context is already initialized } }); } else { this.logger.debug("No ContextLoaderListener registered, as " + "createRootApplicationContext() did not " + "return an application context"); } } protected WebApplicationContext createRootApplicationContext( ServletContext servletContext) { //創(chuàng)建Spring應(yīng)用構(gòu)建器,并進(jìn)行相關(guān)屬性設(shè)置 SpringApplicationBuilder builder = createSpringApplicationBuilder(); StandardServletEnvironment environment = new StandardServletEnvironment(); environment.initPropertySources(servletContext, null); builder.environment(environment); builder.main(getClass()); ApplicationContext parent = getExistingRootWebApplicationContext(servletContext); if (parent != null) { this.logger.info("Root context already created (using as parent)."); servletContext.setAttribute( WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null); builder.initializers(new ParentContextApplicationContextInitializer(parent)); } builder.initializers( new ServletContextApplicationContextInitializer(servletContext)); builder.contextClass(AnnotationConfigEmbeddedWebApplicationContext.class); //調(diào)用configure方法,創(chuàng)建war類型的web項(xiàng)目后,由于編寫SpringBootServletInitializer的子類重寫configure方法,所以此處調(diào)用的是我們定義的子類重寫的configure方法 builder = configure(builder); //通過構(gòu)建器構(gòu)建了一個(gè)Spring應(yīng)用 SpringApplication application = builder.build(); if (application.getSources().isEmpty() && AnnotationUtils .findAnnotation(getClass(), Configuration.class) != null) { application.getSources().add(getClass()); } Assert.state(!application.getSources().isEmpty(), "No SpringApplication sources have been defined. Either override the " + "configure method or add an @Configuration annotation"); // Ensure error pages are registered if (this.registerErrorPageFilter) { application.getSources().add(ErrorPageFilterConfiguration.class); } //啟動(dòng)Spring應(yīng)用 return run(application); } //Spring應(yīng)用啟動(dòng),創(chuàng)建并返回IOC容器 protected WebApplicationContext run(SpringApplication application) { return (WebApplicationContext) application.run(); } }

  ?SpringBootServletInitializer實(shí)例執(zhí)行onStartup方法的時(shí)候會(huì)通過createRootApplicationContext方法來執(zhí)行run方法,接下來的過程就同以jar包形式啟動(dòng)的應(yīng)用的run過程一樣了,在內(nèi)部會(huì)創(chuàng)建IOC容器并返回,只是以war包形式的應(yīng)用在創(chuàng)建IOC容器過程中,不再創(chuàng)建Servlet容器了。

轉(zhuǎn)載于:https://www.cnblogs.com/developerxiaofeng/p/9081689.html

總結(jié)

以上是生活随笔為你收集整理的spring boot中servlet启动原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。