Web原生组件注入(使用web的Servlet、Filter、Listener)
如何在springboot里面使用web原生的组件,一般有两种方式
1.使用Servlet API(要通过标注注解)
Servlet
基本上就是原生使用的格式
@WebServlet
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("6666666666");
}
}
之前我们请求的路径需要在xml里面配置,现在请求路径在注解里配置就可以了
@WebServlet(urlPatterns = "/my")
但是如果想让他生效,我们还需要在主配置类上添加注解
注解的内容可以自定义项目扫描servlet的路径
@ServletComponentScan(basePackages = "com.LALALA.admin")
@SpringBootApplication
public class SpringBoot06Web04InterceptorFileUploadExceptionHandlingApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBoot06Web04InterceptorFileUploadExceptionHandlingApplication.class, args);
}
}
如果里面不写内容,默认是扫描主配置类所在包与其子包
但是现在没有让我们之前配置的拦截器拦截就可以访问,这是为什么?
Filter
@Slf4j
@WebFilter
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("MyFilter初始化完成");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
log.info("MyFilter在工作");
//放行拦截器链路
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
log.info("MyFilter销毁完成");
}
}
而且在这个@WebFilter里面可以填写多个拦截路径,例如现在想拦截css文件
@WebFilter(urlPatterns = {"/css/*","/images/*"})
Listener
@Slf4j
@WebListener
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
log.info("项目初始化完成");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
log.info("项目销毁完成");
}
}
2.使用RegistrationBean
如果我们现在不能动用原生servlet里(也即是我们刚刚写的那三个),而且把这些标注为普通类的时候,就可以使用这个东西完成对原生servlet的使用
现在我们这几个servlet肯定不能使用了
使用RegistrationBean方法
//这是一个配置类
@Configuration
public class MyRegistConfig {
//把这个东西加入容器当中
@Bean
public ServletRegistrationBean myServlet(){
//自己new一个servlet
MyServlet myServlet = new MyServlet();
//把我们的servlet和我们需要映射的路径传入并且返回
return new ServletRegistrationBean(myServlet,"/my");
}
}
@Bean
public FilterRegistrationBean myFilter(){
MyFilter myFilter = new MyFilter();
//这种写法是传入myFilter和上面的myServlet()里面写的啥路径,这玩意就拦截啥路径
//return new FilterRegistrationBean(myFilter,myServlet());
//自己new一个拦截器
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter);
//把拦截器的拦截路径注入
filterRegistrationBean.setUrlPatterns(Arrays.asList("/my","/css/*"));
//返回对象
return filterRegistrationBean;
}
@Bean
public ServletListenerRegistrationBean myListener(){
MyListener myListener = new MyListener();
return new ServletListenerRegistrationBean(myListener);
}
细节,我们需要把这几个组件设置为单实例的
为什么我们自己注入的组件没有经过spring拦截器的拦截?
现在我们servlet的情况
看一下dispatchServlet的自动配置类
给容器中放了一个名字为dispatchservlet的组件
容器中自动配置了 DispatcherServlet 属性绑定到 WebMvcProperties;对应的配置文件配置项是 spring.mvc。
下面还有组件
这个组件的本质还是通过 ServletRegistrationBean<DispatcherServlet> 把 DispatcherServlet 配置进来。
所以这个dispatchServlet就是我们容器中使用的中央处理器组件,但是这个玩意的默认访问路径什么的都在哪呢?——其实都在配置文件里面
我们也可以在配置文件上面修改默认访问路径
Tomcat-Servlet;多个Servlet都能处理到同一层路径,精确优选原则
现在我们的情况就是这样,我们之前访问的也是/my路径,属于精确优先,所以不会走我们spring的拦截器了
切换Web服务器与定制化服务器原理
嵌入式服务器执行流程原理
我们现在不用自己配置tomcar是因为底层已经帮助我们做好了自动配置,但是它是如何做的,已经想使用其他方式的嵌入式服务器如何做?
根据官方文档我们发现,如果现在是web场景,就会把我们的IOC容器变成另外一种形式
但是这个容器的本质其实还是一个普通的IOC
SpringBoot应用启动发现当前是Web应用。web场景包-导入tomcat
web应用会创建一个web版的ioc容器 ServletWebServerApplicationContext
ServletWebServerApplicationContext 启动的时候寻找 ServletWebServerFactory(Servlet 的web服务器工厂---> 生产Servlet 的web服务器)
那平时都会生产哪些?
SpringBoot底层默认有很多的WebServer工厂TomcatServletWebServerFactory, JettyServletWebServerFactory, or UndertowServletWebServerFactory
底层直接会有一个自动配置类。ServletWebServerFactoryAutoConfiguration
○ServletWebServerFactoryAutoConfiguration导入了ServletWebServerFactoryConfiguration(配置类)
那这个配置类都干了什么?
ServletWebServerFactoryConfiguration 配置类 根据动态判断系统中到底导入了那个Web服务器的包。(默认是web-starter导入tomcat包),容器中就有 TomcatServletWebServerFactory
TomcatServletWebServerFactory 创建出Tomcat服务器并启动;TomcatWebServer 的构造器拥有初始化方法initialize---this.tomcat.start();
内嵌服务器,就是手动把启动服务器的代码调用(tomcat核心jar包存在)
如何切换嵌入式服务器
使用pom文件就行
1.在我们的web场景排除tomcat服务器
2.添加我们想使用的服务器依赖
定制化嵌入式服务器
1.修改配置文件 server.xxx
因为我们的服务器自动配置类里的取值都是在server下的配置文件抽取的
在服务器工厂的定制化器中也是在server下的配置文件抽取的
配置文件内容
2.自己写一个web服务器的生产工厂放进去
直接自定义 ConfigurableServletWebServerFactory
3.修改上文所说的容器工厂定制化器
实现 WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>
○把配置文件的值和ServletWebServerFactory 进行绑定
定制化springMVC的原理
springMVC完成自动配置的原理流程
场景starter - xxxxAutoConfiguration - 导入xxx组件 - 绑定xxxProperties -- 绑定配置文件项
定制化的常用操作
1.编写自定义的配置类 xxxConfiguration;+ @Bean替换、增加容器中默认组件;视图解析器
2.修改配置文件
3.修改上文所说的容器工厂定制化器:xxxxxCustomizer;
4.Web应用 编写一个配置类实现 WebMvcConfigurer 的接口即可定制化web功能(可以重写接口里面的方法);+ @Bean给容器中再扩展一些组件
5.@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 没有生效(因为这个组件是被DelegatingWebMvcConfiguration继承的组件)