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

    一、如何定制和修改Servlet容器的相关配置


    1、配置文件(ServerProperties);

    优先级最高

    server.port=8081
    server.context‐path=/crud
    server.tomcat.uri‐encoding=UTF‐8
    //通用的Servlet容器设置
    server.xxx
    //Tomcat的设置
    server.tomcat.xxx

    2、java代码

    2.1 Spring Boot 1.5.10 版本 

    @Bean //一定要将这个定制器加入到容器中 嵌入式的Servlet容器定制器
    public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer(){
      return new EmbeddedServletContainerCustomizer() {
        //定制嵌入式的Servlet容器相关的规则
        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {
          container.setPort(8083);
        }
      };
    }

    2.2 Spring Boot 2.1.0版本

     2.2.1、 方式1  (优先级第二)

    import org.springframework.boot.web.server.WebServerFactoryCustomizer;
    import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
    import org.springframework.stereotype.Component;
    @Component
    public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
        @Override
        public void customize(ConfigurableServletWebServerFactory server) {
            server.setPort(9000);
        }
    }

      2.2.2、方式2 (优先级最低)

    @Bean
    public ConfigurableServletWebServerFactory webServerFactory() {
        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
        factory.setPort(9000);
        // factory.setSessionTimeout(10, TimeUnit.MINUTES);  此方法没找到
        factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notfound.html"));
        return factory;
    }

    二、自定义Servlet容器


    1、Spring Boot 支持的 Servlet容器类型

     2、切换Tomcat容器为jetty容器

     

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions><!-- 排除掉默认的Tomcat web容器-->
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <!-- 引入jetty容器。jetty 适合长连接的场景-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jetty</artifactId><!--  spring-boot-starter-undertow ,不支持JSP-->
    </dependency>
    undertow

    包下:spring-boot-autoconfigure-2.1.0.RELEASE.jar

     

    三、嵌入式Servlet容器自动配置原理Spring Boot 2.1.0版本示例: (注:1.5.10 和2.1.0版本有很大不同)


     Servelt容器的自动配置类

    @Configuration
    @ConditionalOnWebApplication
    @EnableConfigurationProperties(ServerProperties.class)
    public class EmbeddedWebServerFactoryCustomizerAutoConfiguration {
    
        /**
         * Nested configuration if Tomcat is being used.
         */
        @Configuration
        @ConditionalOnClass({ Tomcat.class, UpgradeProtocol.class })
        public static class TomcatWebServerFactoryCustomizerConfiguration {
    
            @Bean
            public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(
                    Environment environment, ServerProperties serverProperties) {
                return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
            }
    
        }
    
        /**
         * Nested configuration if Jetty is being used.
         */
        @Configuration
        @ConditionalOnClass({ Server.class, Loader.class, WebAppContext.class })
        public static class JettyWebServerFactoryCustomizerConfiguration {
    
            @Bean
            public JettyWebServerFactoryCustomizer jettyWebServerFactoryCustomizer(
                    Environment environment, ServerProperties serverProperties) {
                return new JettyWebServerFactoryCustomizer(environment, serverProperties);
            }
    
        }
    
        /**
         * Nested configuration if Undertow is being used.
         */
        @Configuration
        @ConditionalOnClass({ Undertow.class, SslClientAuthMode.class })
        public static class UndertowWebServerFactoryCustomizerConfiguration {
    
            @Bean
            public UndertowWebServerFactoryCustomizer undertowWebServerFactoryCustomizer(
                    Environment environment, ServerProperties serverProperties) {
                return new UndertowWebServerFactoryCustomizer(environment, serverProperties);
            }
    
        }
    
        /**
         * Nested configuration if Netty is being used.
         */
        @Configuration
        @ConditionalOnClass(HttpServer.class)
        public static class NettyWebServerFactoryCustomizerConfiguration {
    
            @Bean
            public NettyWebServerFactoryCustomizer nettyWebServerFactoryCustomizer(
                    Environment environment, ServerProperties serverProperties) {
                return new NettyWebServerFactoryCustomizer(environment, serverProperties);
            }
    
        }
    
    }

     Tomcat 的Server的定制(Jetty、Netty、Undertow 类似)

    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 int getOrder() {
            return 0;
        }
    
        @Override
        public void customize(ConfigurableTomcatWebServerFactory factory) {
            ServerProperties properties = this.serverProperties;
            ServerProperties.Tomcat tomcatProperties = properties.getTomcat();
            PropertyMapper propertyMapper = PropertyMapper.get();
            propertyMapper.from(tomcatProperties::getBasedir).whenNonNull()
                    .to(factory::setBaseDirectory);
            propertyMapper.from(tomcatProperties::getBackgroundProcessorDelay).whenNonNull()
                    .as(Duration::getSeconds).as(Long::intValue)
                    .to(factory::setBackgroundProcessorDelay);
            customizeRemoteIpValve(factory);
            propertyMapper.from(tomcatProperties::getMaxThreads).when(this::isPositive)
                    .to((maxThreads) -> customizeMaxThreads(factory,
                            tomcatProperties.getMaxThreads()));
            propertyMapper.from(tomcatProperties::getMinSpareThreads).when(this::isPositive)
                    .to((minSpareThreads) -> customizeMinThreads(factory, minSpareThreads));
            propertyMapper.from(this::determineMaxHttpHeaderSize).whenNonNull()
                    .asInt(DataSize::toBytes).when(this::isPositive)
                    .to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory,
                            maxHttpHeaderSize));
            propertyMapper.from(tomcatProperties::getMaxSwallowSize).whenNonNull()
                    .asInt(DataSize::toBytes)
                    .to((maxSwallowSize) -> customizeMaxSwallowSize(factory, maxSwallowSize));
            propertyMapper.from(tomcatProperties::getMaxHttpPostSize).asInt(DataSize::toBytes)
                    .when((maxHttpPostSize) -> maxHttpPostSize != 0)
                    .to((maxHttpPostSize) -> customizeMaxHttpPostSize(factory,
                            maxHttpPostSize));
            propertyMapper.from(tomcatProperties::getAccesslog)
                    .when(ServerProperties.Tomcat.Accesslog::isEnabled)
                    .to((enabled) -> customizeAccessLog(factory));
            propertyMapper.from(tomcatProperties::getUriEncoding).whenNonNull()
                    .to(factory::setUriEncoding);
            propertyMapper.from(properties::getConnectionTimeout).whenNonNull()
                    .to((connectionTimeout) -> customizeConnectionTimeout(factory,
                            connectionTimeout));
            propertyMapper.from(tomcatProperties::getMaxConnections).when(this::isPositive)
                    .to((maxConnections) -> customizeMaxConnections(factory, maxConnections));
            propertyMapper.from(tomcatProperties::getAcceptCount).when(this::isPositive)
                    .to((acceptCount) -> customizeAcceptCount(factory, acceptCount));
            customizeStaticResources(factory);
            customizeErrorReportValve(properties.getError(), factory);
        }
    。。。。。。
    }

    Spring Boot 2.1.0 版本的web容器启动流程 (Spring boot 1.5.10版本类似但不同)

    1.Spring boot启动器

    @SpringBootApplication
    public class SpringBootDemo01Application {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringBootDemo01Application.class, args);
        }
    }

    2.run方法启动过程源码分析

    public class SpringApplication {
       //在createApplicationContext()中根据类型classforName()加载 不同类型的  
        public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
                + "annotation.AnnotationConfigApplicationContext";
    
        public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
                + "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
    
        public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
                + "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
    
       //run1调用run2
    public static ConfigurableApplicationContext run(Class<?> primarySource,String... args) { return run(new Class<?>[] { primarySource }, args); }    //run2调用run3 public static ConfigurableApplicationContext run(Class<?>[] primarySources,String[] args) { return new SpringApplication(primarySources).run(args); }
       //run3启动Web服务器
    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); context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); 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; } protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { 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); } } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass", ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass); } private void refreshContext(ConfigurableApplicationContext context) { refresh(context); if (this.registerShutdownHook) { try { context.registerShutdownHook(); } catch (AccessControlException ex) { // Not allowed in some environments. } } } protected void refresh(ApplicationContext applicationContext) { Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); ((AbstractApplicationContext) applicationContext).refresh(); } }
    public abstract class AbstractApplicationContext extends DefaultResourceLoader
            implements ConfigurableApplicationContext {
            
                @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();
                }
            }
        }
        protected void onRefresh() throws BeansException {
            // For subclasses: do nothing by default.
        }
        
    }

    public class ServletWebServerApplicationContext extends GenericWebApplicationContext
            implements ConfigurableWebServerApplicationContext {
            
        @Override
        protected void onRefresh() {
            super.onRefresh();
            try {
                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 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();
        }
            
    }

    spring-boot-2.1.0.RELEASE.jar

  • 相关阅读:
    PV、UV、VV、IP是什么意思?
    多用户远程linux
    实用性阅读指南读书笔记
    在VS添加万能头文件 操作
    sqrt函数实现之卡马克方法
    大端法、小端法及其判断方法
    STL源码剖析之ROUND_UP函数实现原理及其拓展
    海康和多益面经
    小米实习生面试面经
    阿里c++一面面经
  • 原文地址:https://www.cnblogs.com/guchunchao/p/10025311.html
Copyright © 2011-2022 走看看