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

  • 相关阅读:
    svn command line tag
    MDbg.exe(.NET Framework 命令行调试程序)
    Microsoft Web Deployment Tool
    sql server CI
    VS 2010 One Click Deployment Issue “Application Validation did not succeed. Unable to continue”
    mshtml
    大厂程序员站错队被架空,只拿着五折工资!苟活和离职,如何选择?
    揭秘!Windows 为什么会蓝屏?微软程序员竟说是这个原因...
    喂!千万别忘了这个C语言知识!(~0 == -1 问题)
    Linux 比 Windows 更好,谁反对?我有13个赞成理由
  • 原文地址:https://www.cnblogs.com/guchunchao/p/10025311.html
Copyright © 2011-2022 走看看