Spring Boot配置嵌入式Servlet容器

配置嵌入式Servlet容器

  • SpringBoot默认使用Tomcat作为嵌入式的Servlet容器
  • 问题???
  1. 如何定制和修改Servlet容器相关的配置
    • 修改和Server有关的配置(ServerProperties)
    • server.port=8081
      server.context-path=/crud
      
      
      //通用的Servlet容器设置
      server.xxx
      //Tomcat的设置
      server.tomcat.xxx
      
      server.tomcat.uri-encoding=UTF-8
    • 编写一个WebServerFactoryCustomizer:嵌入式的Servlet容器的定制器,来修改Servlet容器的配置
    • 注意:SpringBoot2.0以上版本的EmbeddedServletContainerCustomizerWebServerFactoryCustomizer代替
    • //原先的写法一定要将这个定制器加入到容器中
      @Bean
      public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer(){
          return new EmbeddedServletContainerCustomizer() {
      
              //定制嵌入式的Servlet容器相关的规则
              @Override
              public void customize(ConfigurableEmbeddedServletContainer container) {
                  container.setPort(8083);
              }
          };
      }
      
      //SpringBoot2.0之后的版本的写法
      @Bean
      public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer(){
          return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() {
              @Override
              public void customize(ConfigurableWebServerFactory factory) {
                  factory.setPort(8081);
              }
          };
      }
  2. 注册servlet三大组件【Servlet,Filter,Listener】
    • 由于SpringBoot默认是以jar包的方式启动嵌入式的Servlet容器来启动SpringBoot的web应用,没有web.xml文件。
    • 注册三大组件用以下方式 :
      • ServletRegistrationBean
      • public class MyServlet extends HttpServlet {
        
            //处理get请求
            @Override
            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                doPost(req,resp);
            }
        
            //处理post请求
        
            @Override
            protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                resp.getWriter().write("Hello MyServlet");
            }
        }
        
        //注册三大组件
        @Bean
        public ServletRegistrationBean myServlet(){
            ServletRegistrationBean<Servlet> registrationBean = new ServletRegistrationBean(new MyServlet(),"/myServlet");
            return registrationBean;
        }
      • FilterRegistrationBean
      • public class MyFilter implements Filter {
        
            //Filter的初始化
            @Override
            public void init(FilterConfig filterConfig) throws ServletException {
        
            }
        
            //Filter的过滤
            @Override
            public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
                System.out.println("MyFilter process。。。");
                filterChain.doFilter(servletRequest,servletResponse);
            }
        
            //Filter的销毁
            @Override
            public void destroy() {
        
            }
        }
        
        
        @Bean
        public FilterRegistrationBean myFilter(){
            FilterRegistrationBean registrationBean = new FilterRegistrationBean();
            registrationBean.setFilter(new MyFilter());
            registrationBean.setUrlPatterns(Arrays.asList("/hello","MyServlet"));
            return registrationBean;
        }
      • ServletListenerRegistrationBean
      • public class MyListener implements ServletContextListener {
            //ServletContext初始化,表示Web应用启动了
            @Override
            public void contextInitialized(ServletContextEvent sce) {
                System.out.println("contextInitialized。。。Web应用启动");
            }
        
            @Override
            public void contextDestroyed(ServletContextEvent sce) {
                System.out.println("contextDestroyed。。。当前Web项目销毁");
            }
        }
        
        @Bean
        public ServletListenerRegistrationBean myListener(){
            ServletListenerRegistrationBean registrationBean = new ServletListenerRegistrationBean<MyListener>(new MyListener());
            return registrationBean;
        }
      • SpringBoot帮我们自动SpringMVC的时候,自动的注册SpringMVC的前端控制器DIspatcherServlet
    • SpringBoot能不能支持其他的Servlet容器
      • Jetty(长连接:比如两个人聊天需要这两个人一直架起一个连接)
      • Undertow(不支持JSP,但是他是一个高性能的非阻塞 的Servlet容器,并发性能好)
  3. 替换其他嵌入式Servlet容器
    • Ctrl+H:打开某个类的继承关系
    • 默认支持:

      • Tomcat(默认使用)

      • <!-- 引入Web模块,默认就是使用嵌入式的Tomcat作为Servlet容器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
      • Jetty

      • <!-- 引入web模块,并将TomCat的依赖排除掉-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        
        <!--Jetty(长连接:比如两个人聊天需要这两个人一直架起一个连接) -->
        <!--引入其他的Servlet容器: jetty-->
        <dependency>
            <artifactId>spring-boot-starter-jetty</artifactId>
            <groupId>org.springframework.boot</groupId>
        </dependency>
      • Undertow 

      • <!-- 引入web模块,并将TomCat的依赖排除掉-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        
        <!--Undertow(不支持JSP,但是他是一个高性能的非阻塞 的Servlet容器,并发性能好) -->
        <!--引入其他的Servlet容器: undertow-->
        <dependency>
            <artifactId>spring-boot-starter-undertow</artifactId>
            <groupId>org.springframework.boot</groupId>
        </dependency>
  4. 嵌入式Servlet容器自动配置原理

    • Spring Boot 通过运行主程序类的main()方法来启动Spring Boot 应用,应用启动后调用ServletWebServerApplicationContext这个类中的createWebServer()方法

    • private void createWebServer() {
              WebServer webServer = this.webServer;
              ServletContext servletContext = this.getServletContext();
              if (webServer == null && servletContext == null) {
                      ServletWebServerFactory factory = this.getWebServerFactory();
                      this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
              } else if (servletContext != null) {
                      try {
                              this.getSelfInitializer().onStartup(servletContext);
                      } catch (ServletException var4) {
                              throw new ApplicationContextException("Cannot initialize servlet context", var4);
                      }
              }
              this.initPropertySources();
      } 
    • 该方法最终能够获取到一个与当前应用所导入的Servlet类型相匹配的web服务工厂定制器,例如你的pom文件导入的Servlet依赖为Tomcat:

    • 那么最终会生成Tomcat web服务工厂定制器,定制Servlet容器配置,并通过上述代码中的getWebServer()方法创建对应的Servlet容器,并启动容器

    • ServletWebServerFactory factory = this.getWebServerFactory();
    • 上述代码执行来到EmbeddedWebServerFactoryCustomizerAutoConfiguration(嵌入式web服务工厂定制器自动配置类),根据导入的依赖信息,该配置类会自动创建相应类型的容器工厂定制器(目前Spring Boot 2.x 版本支持tomcat、jetty、undertow、netty),以tomcat为例,这里会创建TomcatWebServerFactoryCustomizer组件

    • //导入的Servlet依赖为Tomcat,则创建Tomcat web服务工厂定制器
      @Configuration(
          proxyBeanMethods = false
      )
      @ConditionalOnClass({Tomcat.class, UpgradeProtocol.class})
      public static class TomcatWebServerFactoryCustomizerConfiguration {
          public TomcatWebServerFactoryCustomizerConfiguration() {
          }
      
          @Bean
          public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
              return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
          }
      }
      
    • 需要注意的是,该自动配置类有一个@EnableConfigurationProperties注解

    • 该注解用于启动指定类ServerProperties(Servlet容器相关的配置类)中的ConfigurationProperties功能,将配置文件中对应的属性值与配置类中的属性值进行映射,并将该配置类添加到IOC容器中

    • 至此,TomcatWebServerFactoryCustomizer组件创建完成,对应的服务配置类也已添加到IOC容器。

    • 下面的处理涉及到一个非常重要的类 WebServerFactoryCustomizerBeanPostProcessor(web服务工厂定制器组件的后置处理器),该类负责在bean组件初始化之前执行初始化工作。
      该类先从IOC容器中获取所有类型为WebServerFactoryCustomizer(web服务工厂定制器)的组件:

    • private Collection<WebServerFactoryCustomizer<?>> getWebServerFactoryCustomizerBeans() {
          return this.beanFactory.getBeansOfType(WebServerFactoryCustomizer.class, false, false).values();
      }
      
    • 通过源码的调试,从IOC容器中获取到5个定制器,其中包含有前面创建的TomcatWebServerFactoryCustomizer定制器:

    • 获取到所有的定制器后,后置处理器调用定制器的customize()方法来给嵌入式的Servlet容器进行配置(默认或者自定义的配置):

    • private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
          ((Callbacks)LambdaSafe.callbacks(WebServerFactoryCustomizer.class, this.getCustomizers(), webServerFactory, new Object[0]).withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)).invoke((customizer) -> {
              customizer.customize(webServerFactory);
          });
      }
      
    • TomcatWebServerFactoryCustomizer定制器调用customize()定制方法,获取到Servlet容器相关配置类ServerProperties,进行自动配置:

    • public void customize(ConfigurableTomcatWebServerFactory factory) {
          ServerProperties properties = this.serverProperties;
          Tomcat tomcatProperties = properties.getTomcat();
          PropertyMapper propertyMapper = PropertyMapper.get();
          tomcatProperties.getClass();
          propertyMapper.from(tomcatProperties::getBasedir).whenNonNull().to(factory::setBaseDirectory);
          tomcatProperties.getClass();
          propertyMapper.from(tomcatProperties::getBackgroundProcessorDelay).whenNonNull().as(Duration::getSeconds).as(Long::intValue).to(factory::setBackgroundProcessorDelay);
          this.customizeRemoteIpValve(factory);
          tomcatProperties.getClass();
          propertyMapper.from(tomcatProperties::getMaxThreads).when(this::isPositive).to((maxThreads) -> {
              this.customizeMaxThreads(factory, tomcatProperties.getMaxThreads());
          });
          tomcatProperties.getClass();
          propertyMapper.from(tomcatProperties::getMinSpareThreads).when(this::isPositive).to((minSpareThreads) -> {
              this.customizeMinThreads(factory, minSpareThreads);
          });
          propertyMapper.from(() -> {
              return this.determineMaxHttpHeaderSize();
          }).when(this::isPositive).to((maxHttpHeaderSize) -> {
              this.customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize);
          });
          tomcatProperties.getClass();
          propertyMapper.from(tomcatProperties::getMaxHttpPostSize).when((maxHttpPostSize) -> {
              return maxHttpPostSize != 0;
          }).to((maxHttpPostSize) -> {
              this.customizeMaxHttpPostSize(factory, maxHttpPostSize);
          });
          tomcatProperties.getClass();
          propertyMapper.from(tomcatProperties::getAccesslog).when(Accesslog::isEnabled).to((enabled) -> {
              this.customizeAccessLog(factory);
          });
          tomcatProperties.getClass();
          propertyMapper.from(tomcatProperties::getUriEncoding).whenNonNull().to(factory::setUriEncoding);
          properties.getClass();
          propertyMapper.from(properties::getConnectionTimeout).whenNonNull().to((connectionTimeout) -> {
              this.customizeConnectionTimeout(factory, connectionTimeout);
          });
          tomcatProperties.getClass();
          propertyMapper.from(tomcatProperties::getMaxConnections).when(this::isPositive).to((maxConnections) -> {
              this.customizeMaxConnections(factory, maxConnections);
          });
          tomcatProperties.getClass();
          propertyMapper.from(tomcatProperties::getAcceptCount).when(this::isPositive).to((acceptCount) -> {
              this.customizeAcceptCount(factory, acceptCount);
          });
          this.customizeStaticResources(factory);
          this.customizeErrorReportValve(properties.getError(), factory);
      }
      
    • 至此,嵌入式Servlet容器的自动配置完成。
  5. 嵌入式Servlet容器启动原理
    • 分析ServletWebServerApplicationContext类的createWebServer()方法:
    • private void createWebServer() {
          WebServer webServer = this.webServer;
          ServletContext servletContext = this.getServletContext();
          if (webServer == null && servletContext == null) {
              ServletWebServerFactory factory = this.getWebServerFactory();
              //执行下面的代码,创建嵌入式的Servlet容器
              this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
          } else if (servletContext != null) {
              try {
                  this.getSelfInitializer().onStartup(servletContext);
              } catch (ServletException var4) {
                  throw new ApplicationContextException("Cannot initialize servlet context", var4);
              }
          }
          this.initPropertySources();
      }
    • 应用启动后,根据导入的依赖信息,创建了相应的Servlet容器工厂,以tomcat为例,创建嵌入式的Tomcat容器工厂TomcatServletWebServerFactory,调用getWebServer()方法创建Tomcat容器:

    • public WebServer getWebServer(ServletContextInitializer... initializers) {
          //创建嵌入式的Tomcat容器
          Tomcat tomcat = new Tomcat();
          File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat");
          tomcat.setBaseDir(baseDir.getAbsolutePath());
          Connector connector = new Connector(this.protocol);
          tomcat.getService().addConnector(connector);
          this.customizeConnector(connector);
          tomcat.setConnector(connector);
          tomcat.getHost().setAutoDeploy(false);
          this.configureEngine(tomcat.getEngine());
          Iterator var5 = this.additionalTomcatConnectors.iterator();
          while(var5.hasNext()) {
              Connector additionalConnector = (Connector)var5.next();
              tomcat.getService().addConnector(additionalConnector);
          }
          this.prepareContext(tomcat.getHost(), initializers);
          return this.getTomcatWebServer(tomcat);
      }
      ...
      protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
          //调用TomcatWebServer类的有参构造器
          //如果配置的端口号>=0,创建Tomcat容器
          return new TomcatWebServer(tomcat, this.getPort() >= 0);
      }
      ...
    • 分析TomcatWebServer类的有参构造器:

    • public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
          this.monitor = new Object();
          this.serviceConnectors = new HashMap();
          Assert.notNull(tomcat, "Tomcat Server must not be null");
          this.tomcat = tomcat;
          this.autoStart = autoStart;
          this.initialize();
          }
    • 执行initialize(),调用start()方法完成了tomcat容器的启动:

    • private void initialize() throws WebServerException {
          logger.info("Tomcat initialized with port(s): " + this.getPortsDescription(false));
          Object var1 = this.monitor;
          synchronized(this.monitor) {
              try {
                  this.addInstanceIdToEngineName();
                  Context context = this.findContext();
                  context.addLifecycleListener((event) -> {
                      if (context.equals(event.getSource()) && "start".equals(event.getType())) {
                          this.removeServiceConnectors();
                      }
                  });
                  //启动tomcat容器
                  this.tomcat.start();
                  this.rethrowDeferredStartupExceptions();
    • 总结:

      • Spring Boot 根据导入的依赖信息,自动创建对应的web服务工厂定制器

      • web服务工厂定制器组件的后置处理器获取所有类型为web服务工厂定制器的组件(包含实现WebServerFactoryCustomizer接口,自定义的定制器组件),依次调用customize()定制接口,定制Servlet容器配置

      • 嵌入式的Servlet容器工厂创建tomcat容器,初始化并启动容器。

 

--------------------------------------分割线--------------------------------------

 

使用外置的Servlet容器

  • 嵌入式Servlet容器:应用打成可执行的jar
    • 优点:简单、便携
    • 缺点:默认不支持JSP、优化定制比较复杂(使用定制器【ServerProperties、自定义WebServerFactoryCustomizer】,自己编写嵌入式Servlet容器的创建工厂【WebServerFactoryCustomizer】)
  • 要用JSP,则需要使用外置的Servlet容器:外面安装Tomcat---应用war包的方式打包
  • 步骤:

    • 必须创建一个war项目;(利用idea创建好目录结构)
    • 将嵌入式的Tomcat指定为provided
    • <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-tomcat</artifactId>
          <scope>provided</scope>
      </dependency>
    • 必须编写一个SpringBootServletInitializer的子类,并重写configure方法
    • public class ServletInitializer extends SpringBootServletInitializer {
      
          @Override
          protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
              //传入SpringBoot应用的主程序
              return application.sources(SpringBoot04WebJspApplication.class);
          }
      
      }
    • 启动服务器就可以使用
  • 原理:

    • jar包:执行SpringBoot主类的main方法,启动Ioc容器,创建嵌入式的Servlet容器
    • war包:启动服务器,服务器启动SpringBoot应用【SpringBootServletInitializer】,再启动Ioc容器
    • 规则: servlet3.0 以上有的规则
      • 8.2.4 
            Shared libraries / runtimes pluggability
        
            In addition to supporting fragments and use of annotations one of the requirements 
            is that not only we be able to plug-in things that are bundled in the WEB-INF/lib
            but also plugin shared copies of frameworks - including being able to plug-in to the 
            web container things like JAX-WS, JAX-RS and JSF that build on top of the web 
            container. The ServletContainerInitializer allows handling such a use case 
            as described below.
        
            The ServletContainerInitializer class is looked up via the jar services API. 
            For each application, an instance of the ServletContainerInitializer is 
            created by the container at application startup time. The framework providing an 
            implementation of the ServletContainerInitializer MUST bundle in the 
            META-INF/services directory of the jar file a file called 
            javax.servlet.ServletContainerInitializer, as per the jar services API, 
            that points to the implementation class of the ServletContainerInitializer.
        
            In addition to the ServletContainerInitializer we also have an annotation -
            HandlesTypes. The HandlesTypes annotation on the implementation of the 
            ServletContainerInitializer is used to express interest in classes that may 
            have annotations (type, method or field level annotations) specified in the value of 
            the HandlesTypes or if it extends / implements one those classes anywhere in the 
            class’ super types. The HandlesTypes annotation is applied irrespective of the 
            setting of metadata-complete.
      • 服务器启动(web应用启动)会创建当前web应用里面每一个jar包里面ServletContainerInitializer实例
      • ServletContainerInitializer的实现放在jar包的META-INF/services文件夹下,有一个名为javax.servlet.ServletContainerInitializer的文件,内容就是ServletContainerInitializer的实现类的全类名
      • 还可以使用@HandlesTypes,在应用启动的时候加载我们感兴趣的类
    • 流程:
      • 启动Tomcat
      • org\springframework\spring-web\5.2.1.RELEASE\spring-web-5.2.1.RELEASE.jar!\META-INF\services\javax.servlet.ServletContainerInitializer,这个文件在Spring的Web模块中,文件内容为:org.springframework.web.SpringServletContainerInitializer,再启动的时候要创建它的实例对象
      • SpringServletContainerInitializer@HandlesTypes(WebApplicationInitializer.class)标注的所有这个类型的类都传入到onStartup()方法的Set<Class<?>>  webAppInitializerClasses 集合中为这些WebApplicationInitializer类型的类创建实例
      • public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
            List<WebApplicationInitializer> initializers = new LinkedList();
            Iterator var4;
            if (webAppInitializerClasses != null) {
                var4 = webAppInitializerClasses.iterator();
        
                while(var4.hasNext()) {
                    Class<?> waiClass = (Class)var4.next();
                    if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
                        try {
                            initializers.add((WebApplicationInitializer)ReflectionUtils.accessibleConstructor(waiClass, new Class[0]).newInstance());
                        } catch (Throwable var7) {
                            throw new ServletException("Failed to instantiate WebApplicationInitializer class", var7);
                        }
                    }
                }
            }
      • 每一个WebApplicationInitializer都调用自己的onStartup()
      • 相当于我们的SpringBootServletInitializer的类会被创建对象,并执行onStartup()方法
      • public class ServletInitializer extends SpringBootServletInitializer {
        
            @Override
            protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
                return application.sources(SpringBoot04WebJspApplication.class);
            }
        
        }
        
        //进入ServletInitializer类的父类,找到其中的onStartup()方法
        public void onStartup(ServletContext servletContext) throws ServletException {
            this.logger = LogFactory.getLog(this.getClass());
            WebApplicationContext rootAppContext = this.createRootApplicationContext(servletContext);
            if (rootAppContext != null) {
                servletContext.addListener(new ContextLoaderListener(rootAppContext) {
                    public void contextInitialized(ServletContextEvent event) {
                    }
                });
            } else {
                this.logger.debug("No ContextLoaderListener registered, as createRootApplicationContext() did not return an application context");
            }
        
        }
      • SpringBootServletInitializer实例执行onStartup()的时候会createRootApplicationContext,创建容器
      • protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) {
            //创建SpringApplicationBuilder构建器
            SpringApplicationBuilder builder = this.createSpringApplicationBuilder();
            builder.main(this.getClass());
            ApplicationContext parent = this.getExistingRootWebApplicationContext(servletContext);
            if (parent != null) {
                this.logger.info("Root context already created (using as parent).");
                servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, (Object)null);
                builder.initializers(new ApplicationContextInitializer[]{new ParentContextApplicationContextInitializer(parent)});
            }
        
            builder.initializers(new ApplicationContextInitializer[]{new ServletContextApplicationContextInitializer(servletContext)});
            builder.contextClass(AnnotationConfigServletWebServerApplicationContext.class);
            
            //调用configure方法,子类重写了这个方法,将SpringBoot的主程序类传入了进来
            builder = this.configure(builder);
            builder.listeners(new ApplicationListener[]{new SpringBootServletInitializer.WebEnvironmentPropertySourceInitializer(servletContext)});
            
            //使用builder创建一个Spring应用
            SpringApplication application = builder.build();
            if (application.getAllSources().isEmpty() && MergedAnnotations.from(this.getClass(), SearchStrategy.TYPE_HIERARCHY).isPresent(Configuration.class)) {
                application.addPrimarySources(Collections.singleton(this.getClass()));
            }
        
            Assert.state(!application.getAllSources().isEmpty(), "No SpringApplication sources have been defined. Either override the configure method or add an @Configuration annotation");
            if (this.registerErrorPageFilter) {
                application.addPrimarySources(Collections.singleton(ErrorPageFilterConfiguration.class));
            }
        
            //启动Spring应用
            return this.run(application);
        }
      • Spring的应用就启动,并且创建Ioc容器
      • public ConfigurableApplicationContext run(String... args) {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            ConfigurableApplicationContext context = null;
            Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
            this.configureHeadlessProperty();
            SpringApplicationRunListeners listeners = this.getRunListeners(args);
            listeners.starting();
        
            Collection exceptionReporters;
            try {
                ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
                ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
                this.configureIgnoreBeanInfo(environment);
                Banner printedBanner = this.printBanner(environment);
                context = this.createApplicationContext();
                exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
                this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        
                //刷新Ioc容器
                this.refreshContext(context);
                this.afterRefresh(context, applicationArguments);
                stopWatch.stop();
                if (this.logStartupInfo) {
                    (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
                }
        
                listeners.started(context);
                this.callRunners(context, applicationArguments);
            } catch (Throwable var10) {
                this.handleRunFailure(context, var10, exceptionReporters, listeners);
                throw new IllegalStateException(var10);
            }
        
            try {
                listeners.running(context);
                return context;
            } catch (Throwable var9) {
                this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
                throw new IllegalStateException(var9);
            }
        }
        
      • 启动Servlet容器,再启动SpringBoot应用

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值