SpringBoot Web原生组件注入(Servlet、Filter、Listener)、嵌入式Servlet容器、定制化原理和方法

目录

一、Web原生组件注入(Servlet、Filter、Listener)

(一)、使用Servlet API

(二)、使用RegistrationBean

二、嵌入式Servlet容器

(一)、切换嵌入式Servlet容器

(二)、定制Servlet容器

三、定制化原理

(一)、定制化的常见方式


一、Web原生组件注入(Servlet、Filter、Listener)

(一)、使用Servlet API

@ServletComponentScan(basePackages = "com.atguigu.admin") :指定原生Servlet组件都放在那里

@WebServlet(urlPatterns = "/my"):效果:直接响应,没有经过Spring的拦截器

@WebFilter(urlPatterns={"/css/*","/images/*"})

@WebListener

推荐可以这种方式;

  1. 原生三大组件,分别对应@Webxxx注解。同时三大组件要想发挥作用,必须都配合@ServletComponentScan注解的使用。
  2. @ServletComponentScan用于配置类上,若不指定basePackages属性,默认是扫描该配置类所属包下的所有内容(包括子包中的内容)。

扩展:DispatchServlet 如何注册进来

  • 容器中自动配置了 DispatcherServlet 属性绑定到 WebMvcProperties;对应的配置文件配置项是 spring.mvc。
  • 通过 ServletRegistrationBean<DispatcherServlet> 把 DispatcherServlet 配置进来。
  • 默认映射的是 / 路径。

 为什么没有经过Spring的拦截器

Tomcat-Servlet;

多个Servlet都能处理到同一层路径,精确优选原则

A: /my/

B: /my/1

即根据精确优先原则,DispatcherServlet处理"/"请求,MyServlet处理"/my"请求,更精确,所以由原生的servlet(Tomcat处理),而只有由DispatcherServlet(Spring)处理的请求才会经过spring的拦截器

 

(二)、使用RegistrationBean

ServletRegistrationBeanFilterRegistrationBean, and ServletListenerRegistrationBean

@Configuration
public class MyRegistConfig {

    @Bean
    public ServletRegistrationBean myServlet(){
        MyServlet myServlet = new MyServlet();

        return new ServletRegistrationBean(myServlet,"/my","/my02");
    }


    @Bean
    public FilterRegistrationBean myFilter(){

        MyFilter myFilter = new MyFilter();
//方式一,拦截ServletRegistrationBean中配置的路径
//        return new FilterRegistrationBean(myFilter,myServlet());
//方式二,设置拦截路径
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter);
        filterRegistrationBean.setUrlPatterns(Arrays.asList("/my","/css/*"));
        return filterRegistrationBean;
    }

    @Bean
    public ServletListenerRegistrationBean myListener(){
        MySwervletContextListener mySwervletContextListener = new MySwervletContextListener();
        return new ServletListenerRegistrationBean(mySwervletContextListener);
    }
}

 

二、嵌入式Servlet容器

(一)、切换嵌入式Servlet容器

  • 默认支持的webServer
    • TomcatJetty, or Undertow
    • ServletWebServerApplicationContext 容器启动寻找ServletWebServerFactory 并引导创建服务器
  • 如何切换服务器
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
//导入undertow依赖,SpringBoot应用启动会自动根据导入的依赖创建对应的容器
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

 

  • 原理
    • SpringBoot应用启动发现当前是Web应用。web场景包-导入tomcat
    • web应用会创建一个web版的ioc容器 ServletWebServerApplicationContext 
    • ServletWebServerApplicationContext  启动的时候寻找 ServletWebServerFactory(Servlet 的web服务器工厂---> Servlet 的web服务器) 
    • SpringBoot底层默认有很多的WebServer工厂;TomcatServletWebServerFactoryJettyServletWebServerFactory, or UndertowServletWebServerFactory
    • 底层直接会有一个自动配置类。ServletWebServerFactoryAutoConfiguration
    • ServletWebServerFactoryAutoConfiguration导入了ServletWebServerFactoryConfiguration(配置类)
    • ServletWebServerFactoryConfiguration 配置类 根据动态判断系统中到底导入了那个Web服务器的包。(默认是web-starter导入tomcat包),容器中就有 TomcatServletWebServerFactory
    • TomcatServletWebServerFactory 创建出Tomcat服务器并启动;TomcatWebServer 的构造器拥有初始化方法initialize---this.tomcat.start();
    • 内嵌服务器,就是手动把启动服务器的代码调用(tomcat核心jar包存在)

(二)、定制Servlet容器

  • 实现 WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>
    • 把配置文件的值和ServletWebServerFactory 进行绑定
  • 修改配置文件 server.xxx
  • 直接自定义 ConfigurableServletWebServerFactory

xxxxxCustomizer:定制化器,可以改变xxxx的默认规则

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);
    }

}

 

三、定制化原理

(一)、定制化的常见方式

(1)修改配置文件;

(2)xxxxxCustomizer;

(3)编写自定义的配置类 xxxConfiguration;+ @Bean替换、增加容器中默认组件;视图解析器

(4)Web应用 编写一个配置类实现 WebMvcConfigurer 即可定制化web功能;+ @Bean给容器中再扩展一些组件

@Configuration
public class AdminWebConfig implements WebMvcConfigurer
  • @EnableWebMvc + WebMvcConfigurer —— @Bean 可以全面接管SpringMVC,所有规则全部自己重新配置; 实现定制和扩展功能
    • 原理
    • 1、WebMvcAutoConfiguration 默认的SpringMVC的自动配置功能类。静态资源、欢迎页.....
    • 2、一旦使用 @EnableWebMvc 。会 @Import(DelegatingWebMvcConfiguration.class)
    • 3、DelegatingWebMvcConfiguration 的 作用,只保证SpringMVC最基本的使用
      • 把所有系统中的 WebMvcConfigurer 拿过来。所有功能的定制都是这些 WebMvcConfigurer 合起来一起生效
      • 自动配置了一些非常底层的组件。RequestMappingHandlerMapping、这些组件依赖的组件都是从容器中获取
      • public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport
    • 4、WebMvcAutoConfiguration 里面的配置要能生效 必须 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
    • 5、所有@EnableWebMvc 导致了 WebMvcAutoConfiguration 没有生效。
  • ... ...
//@EnableWebMvc //表示我们自己全面接管mvc,所有自动配置都会失效,需要自己配置
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {

    /*
     * 定义静态资源行为
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/aa/**")
                .addResourceLocations("classpath:/static/");
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**")  //所有请求都被拦截包括静态资源
                .excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**","/js/**","/aa/**"); //放行的请求
    }
}

总结:

@EnableWebMvc 可以实现全面接管SpringMVC,因此SpringBoot对SpringMVC的默认配置,如欢迎页,静态资源行为等,都会失效。所以我们一般只使用@Configuration + 实现 WebMvcConfigurer接口方式,实现定制化SpringMvc,但不完全接管,此时定制化行为和SpringBoot配置的默认行为都会共同发挥作用。

为什么以上代码对register方法的调用可以同步定制化整个WebMvcConfigurer

  1. 当我们实现WebMvcConfigurer接口并重写了指定的方法以实现定制化后,所有的WebMvcConfigurer实例的同一功能方法都会被同步定制化修改,而其他的功能又能保持正常运行不变。
  2. WebMvcConfigurer 的大多数方法都有形参如regisiter,而形参都是从容器中获取到的,换而言之,系统中的多个WebMvcConfigurer 实例的同一方法所使用的形参如regisiter都是同一个。当我们定制化SpringMvc时,更多是对形参regisiter的相关操作,因此会对系统中的所有的WebMvcConfigurer实例的同一方法产生作用。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zoeil

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值