springboot10-servlet自定义配置

嵌入式servlet配置修改

SpringBoot默认使用Tomcat作为嵌入式的Servlet容器

在这里插入图片描述

嵌入式tomcat:tomca-embed-core

问题?

1)、如何定制和修改Servlet容器相关配置;

​ 1.修改和server有关的配置:(ServerProperties.class)

server.port=8081
server.servlet.context-path=/ogj
server.tomcat.uri-encoding=UTF-8

//通用的Server配置
server.xxx
//Tomcat的设置
server.tomcat.xxx

​ 前几个版本还可以自定义接口设置,但是在springboot2.x以后取消了该接口,所有Servlet配置在配置文件中配置。

对于SpringBoot中可以用xxxCustomize进行定制配置。

2. 注册Servlet三大组件【Servlet、Filter、Listener】

由于SpringBoot默认是以jar包的方式启动嵌入式的Servlet容器来启动SpringBoot的web应用,没有web.xml文件。

所以SpringBoot使用三大组件来配置web:Servlet、Filter、Listener**

注册三大组件的方式:

1、ServletRegistrationBean

定义servlet

public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("-----------doGet----------------");
        //此处不能访问父方法,否则会405
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("-----------doPost----------------");
        resp.getWriter().write("Hello MyServlet");
    }
}

注册servlet:

@Bean
public ServletRegistrationBean myServlet(){
    ServletRegistrationBean registrationBean =
            new ServletRegistrationBean(new MyServlet(), "/myServlet");
    return registrationBean;
}

2、FilterRegistrationBean

定义Filter

public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("-----Filter-----");
        filterChain.doFilter(servletRequest,servletResponse);
    }
}

注册Filter

//注册Filter 拦截URL
    @Bean
    public FilterRegistrationBean myFilter(){
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(new MyFilter());
        registrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet"));
        return registrationBean;
    }

3、ServletListenerRegistrationBean

定义Listener:

public class Mylistener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("contextInitialized...web应用启动");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("contextDestroy...web项目销毁");
    }
}

注册Listener:

//注册Listener 监听器
    @Bean
    public ServletListenerRegistrationBean<Mylistener> myListener(){
        ServletListenerRegistrationBean<Mylistener> registrationBean
                = new ServletListenerRegistrationBean<>(new Mylistener());
        return registrationBean;

    }

SpringBoot帮助我们自动SpringMVC的时候,自动的注册SpringMVC的前端控制器:DispatcherServlet;

配置类:DispatcherServletAutoConfiguration

ctrl+n查找该类源码可得自动注册方法:dispatcherServletRegistration

@Bean(
            name = {"dispatcherServletRegistration"}
        )
        @ConditionalOnBean(
            value = {DispatcherServlet.class},
            name = {"dispatcherServlet"}
        )
        public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet, WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {
            DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet, webMvcProperties.getServlet().getPath());
            //默认拦截: / 所有请求;包括静态资源,但是不拦截jsp请求,  /* 会拦截jsp
            //可以通过server.servletpath来修改SpringMVC前端控制器拦截的请求路径
           
            registration.setName("dispatcherServlet");
            registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
            multipartConfig.ifAvailable(registration::setMultipartConfig);
            return registration;
        }

在这里插入图片描述

在这里插入图片描述

  • 默认拦截: / 所有请求; 包括静态资源,但是不拦截jsp请求, /* 会拦截jsp

  • 可以通过server.servletpath来修改SpringMVC前端控制器拦截的请求路径

2)、SpringBoot能不能支持其他的Servlet容器;

3)、替换为其他嵌入式Servlet容器

默认支持:Tomcat、Jetty、Undertow,新版本SpringBoot中还添加了Netty新机制容器;默认使用tomcat

在这里插入图片描述

<!--引入web模块-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
<!--引入web模块的时候就是默认使用的tomcat作为Servlet容器-->

切换方式:

​ 1、在pow中排除tomcat的依赖;

​ 2、添加jetty(Undertow)的依赖; Undertow不支持jsp组件;

<!--引入web模块-->
    <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>

    <!--配置其他Servlet容器-->
    <dependency>
        <artifactId>spring-boot-starter-jetty</artifactId>
        <groupId>org.springframework.boot</groupId>
    </dependency>

4)、嵌入式Servlet容器自动配置原理:

新版本SpringBoot2.x在该类中进行自动配置:EmbeddedWebServerFactoryCustomizerAutoConfiguration

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnWebApplication
@EnableConfigurationProperties({ServerProperties.class})
public class EmbeddedWebServerFactoryCustomizerAutoConfiguration {
    //配置NettyWebServer
    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnClass({HttpServer.class})
    public static class NettyWebServerFactoryCustomizerConfiguration {
        public NettyWebServerFactoryCustomizerConfiguration() {
        }

        @Bean
        public NettyWebServerFactoryCustomizer nettyWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
            return new NettyWebServerFactoryCustomizer(environment, serverProperties);
        }
    }
    //配置Undertow
    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnClass({Undertow.class, SslClientAuthMode.class})
    public static class UndertowWebServerFactoryCustomizerConfiguration {
        public UndertowWebServerFactoryCustomizerConfiguration() {
        }

        @Bean
        public UndertowWebServerFactoryCustomizer undertowWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
            return new UndertowWebServerFactoryCustomizer(environment, serverProperties);
        }
    }
    //配置jetty
    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnClass({Server.class, Loader.class, WebAppContext.class})
    public static class JettyWebServerFactoryCustomizerConfiguration {
        public JettyWebServerFactoryCustomizerConfiguration() {
        }

        @Bean
        public JettyWebServerFactoryCustomizer jettyWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
            return new JettyWebServerFactoryCustomizer(environment, serverProperties);
        }
    }
    //配置Tomcat
    @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);
        }
    }
}

新版本的SpringBoot2.x使用的自定义配置已经不是传入容器了,而是传入xxWebServerFactoryCustomizer,作为自定义Servlet容器配置。

我们还可以看到以下几个xxWebServletFactoryCustomizer配置类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EMFErJI6-1583925810401)(C:\Users\ouguangji\AppData\Roaming\Typora\typora-user-images\image-20200311090632948.png)]

Tomcat配置过程(该代码位于源码:TomcatWebServerFactoryCustomizer):

public TomcatWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
        this.environment = environment;
        this.serverProperties = serverProperties;
    }

//customer的自动配置
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(this.serverProperties.getMaxHttpHeaderSize()).whenNonNull().asInt(DataSize::toBytes).when(this::isPositive).to((maxHttpHeaderSize) -> {
            this.customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize);
        });
        tomcatProperties.getClass();
        propertyMapper.from(tomcatProperties::getMaxSwallowSize).whenNonNull().asInt(DataSize::toBytes).to((maxSwallowSize) -> {
            this.customizeMaxSwallowSize(factory, maxSwallowSize);
        });
        tomcatProperties.getClass();
        propertyMapper.from(tomcatProperties::getMaxHttpFormPostSize).asInt(DataSize::toBytes).when((maxHttpFormPostSize) -> {
            return maxHttpFormPostSize != 0;
        }).to((maxHttpFormPostSize) -> {
            this.customizeMaxHttpFormPostSize(factory, maxHttpFormPostSize);
        });
        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::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);
        });
        tomcatProperties.getClass();
        propertyMapper.from(tomcatProperties::getProcessorCache).to((processorCache) -> {
            this.customizeProcessorCache(factory, processorCache);
        });
        tomcatProperties.getClass();
        propertyMapper.from(tomcatProperties::getRelaxedPathChars).as(this::joinCharacters).whenHasText().to((relaxedChars) -> {
            this.customizeRelaxedPathChars(factory, relaxedChars);
        });
        tomcatProperties.getClass();
        propertyMapper.from(tomcatProperties::getRelaxedQueryChars).as(this::joinCharacters).whenHasText().to((relaxedChars) -> {
            this.customizeRelaxedQueryChars(factory, relaxedChars);
        });
        this.customizeStaticResources(factory);
        this.customizeErrorReportValve(properties.getError(), factory);
    }

由于Servlet加载和配置原理在SpringBoot2.X重构,这就不探究了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章