zoukankan      html  css  js  c++  java
  • 配置嵌入式Servlet容器

    定制和修改Servlet容器的server相关配置

    1. 修改和server有关的配置

      server.port=8081
      server.context-path=/crud
      
      server.tomcat.uri-encoding=UTF-8
      
      //通用的Servlet容器设置
      server.xxx
      //Tomcat的设置
      server.tomcat.xxx
      
    2. 编写一个EmbeddedServletContainerCustomizer,2.0以后改为WebServerFactoryCustomizer:嵌入式的Servlet容器的定制器;来修改Servlet容器的配置,代码方式的配置会覆盖配置文件的配置(和其他Customizer一起代理生成)

      @Configuration
      public class MyMvcConfig implements WebMvcConfigurer {
          @Bean
          public WebServerFactoryCustomizer webServerFactoryCustomizer() {
              return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() {
                  @Override
                  public void customize(ConfigurableWebServerFactory factory) {
                      factory.setPort(8088);
                  }
              };
          }
      ......
      

    修改server配置原理

    ServletWebServerFactoryAutoConfiguration在向容器中添加web容器时还添加了一个组件

    ==

    BeanPostProcessorsRegistrar:后置处理器注册器(实现了BeanPostProcessor,动态代理后后置处理生成一些Bean)

        public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
            private ConfigurableListableBeanFactory beanFactory;
    
            public BeanPostProcessorsRegistrar() {...}
    
            public void setBeanFactory(BeanFactory beanFactory) throws BeansException {...}
    
            public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
                if (this.beanFactory != null) {
                    //注册了下面的组件
                  registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
    					WebServerFactoryCustomizerBeanPostProcessor.class);
                }
            }
    
            private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name, Class<?> beanClass) {...}
        }
    
    
    
    public class WebServerFactoryCustomizerBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
    
        ......
    
        //在Bean初始化之前
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            //判断添加的Bean是不是WebServerFactory类型的
            if (bean instanceof WebServerFactory) {
                this.postProcessBeforeInitialization((WebServerFactory)bean);
            }
    
            return bean;
        }
    
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
    
        private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
            //获取所有的定制器,调用每一个定制器的customize方法来给Servlet容器进行属性赋值;
            ((Callbacks)LambdaSafe.callbacks(WebServerFactoryCustomizer.class, this.getCustomizers(), webServerFactory, new Object[0]).withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)).invoke((customizer) -> {
                customizer.customize(webServerFactory);
            });
        }
    

    1. BeanPostProcessor简介

    BeanPostProcessor是Spring IOC容器给我们提供的一个扩展接口。接口声明如下:

    public interface BeanPostProcessor {
     //bean初始化方法调用前被调用
     Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
     //bean初始化方法调用后被调用
     Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
    }
    

    运行顺序

    Spring IOC容器实例化Bean
    调用BeanPostProcessor的postProcessBeforeInitialization方法
    调用bean实例的初始化方法
    调用BeanPostProcessor的postProcessAfterInitialization方法

    image.png

    2. BeanPostProcessor实例

    /**
     * 后置处理器:初始化前后进行处理工作
     * 将后置处理器加入到容器中
     */
    @Component
    public class MyBeanPostProcessor implements BeanPostProcessor {
    
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            // TODO Auto-generated method stub
            System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean);
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            // TODO Auto-generated method stub
            System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean);
            return bean;
        }
    
    }
    

    3. BeanFactoryPostProcessor简介

    bean工厂的bean属性处理容器,说通俗一些就是可以管理我们的bean工厂内所有的beandefinition(未实例化)数据,可以随心所欲的修改属性。

    4. BeanFactoryPostProcessor实例

    @Component
    public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            System.out.println("MyBeanFactoryPostProcessor...postProcessBeanFactory...");
            int count = beanFactory.getBeanDefinitionCount();
            String[] names = beanFactory.getBeanDefinitionNames();
            System.out.println("当前BeanFactory中有"+count+" 个Bean");
            System.out.println(Arrays.asList(names));
        }
    
    }
    

    区别:

    注册BeanFactoryPostProcessor的实例,需要重载

    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

    通过beanFactory可以获取bean的示例或定义等。同时可以修改bean的属性,这是和BeanPostProcessor最大的区别。

    关于如何AutoConfiguration中Customizer配置文件是如何设置的,参考EmbeddedWebServerFactoryCustomizerAutoConfiguration类,最后若是常用设置,还是使用propertis配置更为方便。

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnWebApplication
    @EnableConfigurationProperties(ServerProperties.class)
    public class EmbeddedWebServerFactoryCustomizerAutoConfiguration {
    
    	/**
    	 * Nested configuration if Tomcat is being used.
    	 */
    	@Configuration(proxyBeanMethods = false)
        // 若嵌入式Servlet容器导入的为Tomcat的依赖
    	@ConditionalOnClass({ Tomcat.class, UpgradeProtocol.class })
    	public static class TomcatWebServerFactoryCustomizerConfiguration {
    
    		@Bean
    		public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(Environment environment,
    				ServerProperties serverProperties) {
    			return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
    		}
    }
    
    

    该类也实现了WebServerFactoryCustomizer,只是customize方法调用的参数配置不一样,最终都由BeanPostProcessorsRegistrar在创建容器前动态代理与其他WebServerFactoryCustomizer互补配置生成代理类。

    public class TomcatWebServerFactoryCustomizer
    		implements WebServerFactoryCustomizer,<ConfigurableTomcatWebServerFactory>, Ordered {
    
    	private final Environment environment;
    
    	private final ServerProperties serverProperties;
    
    	public TomcatWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
    		this.environment = environment;
    		this.serverProperties = serverProperties;
    	}
        @Override
    	public void customize(ConfigurableTomcatWebServerFactory factory) {
            ·····
        }
    }
    
    

    总结:

    1. SpringBoot根据导入的依赖情况,给容器中添加相应的XXXServletWebServerFactory

    2. 容器中某个组件要创建对象就会惊动后置处理器 webServerFactoryCustomizerBeanPostProcessor

      只要是嵌入式的是Servlet容器工厂,后置处理器就会工作;

    3. 后置处理器,从容器中获取所有的WebServerFactoryCustomizer,调用定制器的定制方法给工厂添加配置

    替换为其他嵌入式web容器

    如果要换成其他的就把Tomcat的依赖排除掉,然后引入其他嵌入式Servlet容器的以来,如JettyUndertow

            <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>
    
            <dependency>
                <artifactId>spring-boot-starter-jetty</artifactId>
                <groupId>org.springframework.boot</groupId>
            </dependency>
            <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>
    
            <dependency>
                <artifactId>spring-boot-starter-undertow</artifactId>
                <groupId>org.springframework.boot</groupId>
            </dependency>
    

    替换原理

    查看web容器自动配置类

    1. ServletWebServerFactoryAutoConfiguration在当是服务端的情况下必然启动的配置,在其中完成2版本之前的AnnotationConfigEmbeddedApplicationContext的Embedded判断
    2. xxxWebServerFactoryCustomizer嵌入式web服务器对于自己serverproperties的servler参数的详细设置。
    3. @ImportServletWebServerFactoryConfiguration.EmbeddedTomcat.class时会判断是否符合条件,他将读取EmbeddedWebServerFactoryCustomizerAutoConfiguration中的TomcatWebServerFactoryCustomizer和自己配置的WebServerFactoryCustomizer来生成factory
    4. 若是不是内嵌的servlet,则将下面的两个生效在外部的servlet上(可能)(可能在servletContext上区分除了外部和内嵌)
    5. ServletWebServerFactoryCustomizer读取了配置文件的基本配置,对应于所有内嵌容器中中的server.xml+web.xml中的通用部分提取。
    6. TomcatServletWebServerFactoryCustomizer定制的若是tomcat服务器,则进行一些server中对于servlet的特殊参数的设置

    2.0以下是:EmbeddedServletContainerAutoConfiguration

    ServletWebServerFactoryAutoConfiguration:嵌入式的web服务器自动配置

    @Configuration(
        proxyBeanMethods = false
    )
    @AutoConfigureOrder(-2147483648)
    @ConditionalOnClass({ServletRequest.class})
    @ConditionalOnWebApplication(
        type = Type.SERVLET
    )
    @EnableConfigurationProperties({ServerProperties.class})
    
    //---看这里---
    @Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, 							ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
    		ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
    		ServletWebServerFactoryConfiguration.EmbeddedUndertow.class})
    public class ServletWebServerFactoryAutoConfiguration {
        ···
    }
    

    ServletWebServerFactoryConfiguration.EmbeddedTomcat.class

    @Configuration(proxyBeanMethods = false)
    class ServletWebServerFactoryConfiguration {
    
    	@Configuration(proxyBeanMethods = false)
            //判断当前是否引入了Tomcat依赖;
    	@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
        	/**
          *判断当前容器没有用户自己定义ServletWebServerFactory:嵌入式的web服务器工厂;
          *作用:创建嵌入式的web服务器
          */
    	@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
    	static class EmbeddedTomcat {
    
    		@Bean
    		TomcatServletWebServerFactory tomcatServletWebServerFactory(
    				ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
    				ObjectProvider<TomcatContextCustomizer> contextCustomizers,
    				ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
    			TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
    			factory.getTomcatConnectorCustomizers()
    					.addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));
    			factory.getTomcatContextCustomizers()
    					.addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));
    			factory.getTomcatProtocolHandlerCustomizers()
    					.addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));
    			return factory;
    		}
    
    	}
    

    我们可以实现ServletWebServerFactory接口来自定义ServletWebServerFactory,它默认为我们实现了常用的服务器。

    TomcatServletWebServerFactory为例,接口只要求实现一个便是,getWebServer方法,下面是TomcatServletWebServerFactory类

        public WebServer getWebServer(ServletContextInitializer... initializers) {
            if (this.disableMBeanRegistry) {
                Registry.disableRegistry();
            }
    
            //创建一个Tomcat
            Tomcat tomcat = new Tomcat();
    
            //配置Tomcat的基本环境,(tomcat的配置都是从本类获取的,tomcat.setXXX)
            File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat");
            tomcat.setBaseDir(baseDir.getAbsolutePath());
            Connector connector = new Connector(this.protocol);
            connector.setThrowOnFailure(true);
            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);
    
            //将配置好的Tomcat传入进去,返回一个WebServer;并且启动Tomcat服务器
            return this.getTomcatWebServer(tomcat);
        }
    
    • 依据不同的服务器类型选择,生成不同的服务器,用多个WebServerFactoryCustomizer最后代理生成的TomcatServletWebServerFactory(由修改配置原理的2和3配置互补生成同一种类型的factory)
    • 可以自己自定义或内嵌的生成相应的xxxServletebServerFactory。

    内置Servlet的启动原理

    内置与外置的差别在于createApplicationContext()的的结果不同,

    1. SpringApplication.run
    2. SpringBoot应用启动运行run方法
    public ConfigurableApplicationContext run(String... args) {
       StopWatch stopWatch = new StopWatch();
       stopWatch.start();
       ConfigurableApplicationContext context = null;
       Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
       configureHeadlessProperty();
       SpringApplicationRunListeners listeners = getRunListeners(args);
       listeners.starting();
       try {
          ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
          ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
          configureIgnoreBeanInfo(environment);
          Banner printedBanner = printBanner(environment);
           
          // 若是默认配置且为web应用怎会调用AnnotationConfigServletWebServerApplicationContext,1.5的版本仍是需要AnnotationConfigEmbeddedApplicationContext
          context = createApplicationContext();
           /*try {
    				switch (this.webApplicationType) {
    				case SERVLET:
    					contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
    					break;
    				case REACTIVE:
    					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
    					break;
    				default:
    					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
    				}
    	 */
          exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                new Class[] { ConfigurableApplicationContext.class }, context);
          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);
          }
          listeners.started(context);
          callRunners(context, applicationArguments);
       }
       catch (Throwable ex) {
          handleRunFailure(context, ex, exceptionReporters, listeners);
          throw new IllegalStateException(ex);
       }
    
       try {
          listeners.running(context);
       }
       catch (Throwable ex) {
          handleRunFailure(context, ex, exceptionReporters, null);
          throw new IllegalStateException(ex);
       }
       return context;
    }
    
    1. 查看ServletWebServerApplicationContext类的refresh方法
    	@Override
    	public final void refresh() throws BeansException, IllegalStateException {
    		try {
    			super.refresh();
    		}
    		catch (RuntimeException ex) {
    			WebServer webServer = this.webServer;
    			if (webServer != null) {
    				webServer.stop();
    			}
    			throw ex;
    		}
    	}
    
    1. 调用其父类的refresh方法,其中try中对于bean对象的刷新全都在ServletWebServerApplicationContext中重写了,这里提供一个规范与注释,易于维护与理解,
    @Override
    public void refresh() throws BeansException, IllegalStateException {
       synchronized (this.startupShutdownMonitor) {
          // Prepare this context for refreshing.
          prepareRefresh();
    
          // Tell the subclass to refresh the internal bean factory.
          ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
          // Prepare the bean factory for use in this context.
          prepareBeanFactory(beanFactory);
    
          try {
             // Allows post-processing of the bean factory in context subclasses.
             postProcessBeanFactory(beanFactory);
    
             // Invoke factory processors registered as beans in the context.
             invokeBeanFactoryPostProcessors(beanFactory);
    
             // Register bean processors that intercept bean creation.
             registerBeanPostProcessors(beanFactory);
    
             // Initialize message source for this context.
             initMessageSource();
    
             // Initialize event multicaster for this context.
             initApplicationEventMulticaster();
    
             // Initialize other special beans in specific context subclasses.
             onRefresh();
    
             // Check for listener beans and register them.
             registerListeners();
    
             // Instantiate all remaining (non-lazy-init) singletons.
             finishBeanFactoryInitialization(beanFactory);
    
             // Last step: publish corresponding event.
             finishRefresh();
          }
    
          catch (BeansException ex) {
             if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                      "cancelling refresh attempt: " + ex);
             }
    
             // Destroy already created singletons to avoid dangling resources.
             destroyBeans();
    
             // Reset 'active' flag.
             cancelRefresh(ex);
    
             // Propagate exception to caller.
             throw ex;
          }
    
          finally {
             // Reset common introspection caches in Spring's core, since we
             // might not ever need metadata for singleton beans anymore...
             resetCommonCaches();
          }
       }
    }
    
    1. 对于servlet的启动,重要的是onRefresh()方法
    @Override
    protected void onRefresh() {
        //调用父类的onRefresh,输出了时间戳
       super.onRefresh();
       try {
           //创建服务器服务
          createWebServer();
       }
       catch (Throwable ex) {
          throw new ApplicationContextException("Unable to start web server", ex);
       }
    }
    

    7.createWebServer();

    private void createWebServer() {
       WebServer webServer = this.webServer;
       ServletContext servletContext = getServletContext();
       if (webServer == null && servletContext == null) {//可能在这里区分出了外部和内嵌的区别
           
           //获取当前系统由配置类自动生成到容器中的factory
          ServletWebServerFactory factory = getWebServerFactory();
           //用该factory生成一个对应类型的服务器,并在xxxWebServer的初始化时会启动xxx服务器。
           // 其中xxxServletWebServerFactory(若是tomcat)则会new tomcat和StandardServer等Tomcat外置服务器中同样 org.apache.catalina包中的类,之后和tomcat一样的启动流程。
          this.webServer = factory.getWebServer(getSelfInitializer());
          getBeanFactory().registerSingleton("webServerGracefulShutdown",
                new WebServerGracefulShutdownLifecycle(this.webServer));
          getBeanFactory().registerSingleton("webServerStartStop",
                new WebServerStartStopLifecycle(this, this.webServer));
       }
       else if (servletContext != null) {
          try {
             getSelfInitializer().onStartup(servletContext);
          }
          catch (ServletException ex) {
             throw new ApplicationContextException("Cannot initialize servlet context", ex);
          }
       }
       initPropertySources();
    }
    
    • 若获取的是tomcat服务器,则配置后启动
    @Override
    public WebServer getWebServer(ServletContextInitializer... initializers) {
       if (this.disableMBeanRegistry) {
          Registry.disableRegistry();
       }
       // 给将配置的参数放置在tomcat类中以便初始化何启动
       // tomcat也为org.apache.catalina.startup包中的类,用于内嵌式时自己启动,自己配置server,service等组件,不同于用批处理命令开启读取xml文件创建server的方式
       Tomcat tomcat = new Tomcat();
       File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
       tomcat.setBaseDir(baseDir.getAbsolutePath());
       Connector connector = new Connector(this.protocol);
       connector.setThrowOnFailure(true);
       tomcat.getService().addConnector(connector);
       customizeConnector(connector);
       tomcat.setConnector(connector);
       tomcat.getHost().setAutoDeploy(false);
       configureEngine(tomcat.getEngine());
       for (Connector additionalConnector : this.additionalTomcatConnectors) {
          tomcat.getService().addConnector(additionalConnector);
       }
       prepareContext(tomcat.getHost(), initializers);
        //获取TomcatWebServer,设置启动级别,初始化若是1则同时启动
       return getTomcatWebServer(tomcat);
    }
    
    1. 嵌入式的Servlet容器创建对象并启动Servlet容器;

    2. 嵌入式的Servlet容器启动后,再将ioc容器中剩下没有创建出的对象获取出来(Controller,Service等);

    使用外置的Servlet容器

    1. 将项目的打包方式改为war

    2. 编写一个类继承SpringBootServletInitializer,并重写configure方法,调用参数的sources方法springboot启动类传过去然后返回

      public class ServletInitializer extends SpringBootServletInitializer {
          @Override
          protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
              return application.sources(HelloSpringBootWebApplication.class);
          }
      }
      
    3. 然后把tomcat的依赖范围改为provided

          <dependencies>
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-web</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-tomcat</artifactId>
                  <version>2.2.1.RELEASE</version>
                  <scope>provided</scope>
              </dependency>
      
              ......
      
          </dependencies>
      
    4. 最后就可以把项目打包成war放到tomcat中了

    5. 在IDEA中可以这样配置

      1574247311250

    6. 在创建项目时使用Spring Initializr创建选择打包方式为war,1,2,3步骤会自动配置

    使用外置Servlet的原理

    TODO 2019-11-20

    1. Servlet3.0标准ServletContainerInitializer扫描所有jar包中METAINF/services/javax.servlet.ServletContainerInitializer文件指定的类并加载

    2. 还可以使用@HandlesTypes,在应用启动的时候加载我们感兴趣的类;

    3. 在spring-web-xxx.jar包中的METAINF/services下有javax.servlet.ServletContainerInitializer这个文件

      文件中的类是:

      org.springframework.web.SpringServletContainerInitializer
      

      对应的类:

      @HandlesTypes({WebApplicationInitializer.class})
      public class SpringServletContainerInitializer implements ServletContainerInitializer {
          public SpringServletContainerInitializer() {
          }
      
          public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
      
              ......
      
    4. SpringServletContainerInitializer将@HandlesTypes(WebApplicationInitializer.class)标注的所有这个类型的类都传入到onStartup方法的Set<Class<?>>;为这些WebApplicationInitializer类型的类创建实例;

    5. 每一个WebApplicationInitializer都调用自己的onStartup方法;

    6. WebApplicationInitializer的实现类

    1. 相当于我们的SpringBootServletInitializer的类会被创建对象,并执行onStartup方法

    2. SpringBootServletInitializer实例执行onStartup的时候会createRootApplicationContext;创建容器

      protected WebApplicationContext createRootApplicationContext(
            ServletContext servletContext) {
          //1、创建SpringApplicationBuilder
         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);
      
          //调用configure方法,子类重写了这个方法,将SpringBoot的主程序类传入了进来
         builder = configure(builder);
      
          //使用builder创建一个Spring应用
         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);
         }
          //启动Spring应用
         return run(application);
      }
      
    3. Spring的应用就启动并且创建IOC容器

      public ConfigurableApplicationContext run(String... args) {
         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);
           // 若是web应用则调用AnnotationConfigServletWebServerApplicationContext,1.5的版本仍是需要AnnotationConfigEmbeddedApplicationContext
            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);
         }
      }
      
  • 相关阅读:
    Linux内核的总结认识
    服务器的基本问题避免
    Linux中多线程信号的处理
    gdb调试
    TCP数据包的封包和拆包
    网络TCp数据的传输设计(黏包处理)
    InputArray和OutputArray
    UTF8转unicode说明
    C++使用标准库的栈和队列
    resize函数有五种插值算法
  • 原文地址:https://www.cnblogs.com/eternal-heathens/p/13601289.html
Copyright © 2011-2022 走看看