一、闲话
今天本来准备偷懒一下,但是打开CSDN之前跟自己说,如果今天又涨粉丝了,那么就学习一下
学多学少都要学,打开一看,哈哈哈,多了三十多个粉丝,只能带着开心来继续学习咯
二、注入Web原生组件
1、使用Servlet API
关于servlet,可以看下博主之前写的博客【SpringMVC】MVC架构与Servlet
注意,如果要是下面的注解生效,还需要使用@ServletComponentScan注解
@ServletComponentScan(basePackages = “com.decade.servlet”) :指定原生Servlet组件都放在哪里,我们一般将他放在主启动类上
- 注入Servlet:使用@WebServlet
package com.decade.servlet;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
@WebServlet(urlPatterns = {"/myServlet"}) // 配置指定url,请求转发到此servlet
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().print("test OK!");
}
}
效果:直接响应,我们要思考一下/my
请求为什么没有经过Spring的拦截器?
- 注入Filter:使用@WebFilter
package com.decade.servlet;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@Slf4j
@WebFilter(urlPatterns = {"/css/*", "/images/*"}) // 配置过滤器过滤的请求
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("filter初始化完成!");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
log.info("过滤器生效!");
// 完成过滤逻辑之后,放行
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
log.info("filter销毁完成!");
}
}
- 注入Listener:使用@WebListener
package com.decade.servlet;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@Slf4j
@WebListener
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
log.info("MyListener监听到项目初始化完成!");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
log.info("MyListener监听到项目销毁!");
}
}
启动项目进行验证
2、使用RegistrationBean
创建一个配置类,使用@Bean注解将servlet、filter和listener注册到容器中去
我们结合一个实例来验证一下
首先我们将上面创建的三个类上面的@WebServlet、@WebFilter和@WebListener删除
然后自己新建一个配置类
package com.decade.servlet;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
// 保证依赖的组件是单实例的
@Configuration(proxyBeanMethods = true)
public class MyServletConfig {
@Bean
public ServletRegistrationBean myServlet() {
final MyServlet myServlet = new MyServlet();
// 设置对应此servlet的请求路径
return new ServletRegistrationBean(myServlet, "/myServlet", "/myServlet2");
}
@Bean
public FilterRegistrationBean myFilter() {
final MyFilter myFilter = new MyFilter();
// 设置要过滤的请求,即对应这个请求的servlet
//return new FilterRegistrationBean(myFilter, myServlet());
// 方式二:使用setUrlPatterns配置要拦截的请求
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter);
filterRegistrationBean.setUrlPatterns(Arrays.asList("/css/*", "/myServlet", "/myServlet2"));
return filterRegistrationBean;
}
@Bean
public ServletListenerRegistrationBean myListener() {
final MyListener myListener = new MyListener();
return new ServletListenerRegistrationBean(myListener);
}
}
验证同样生效
3、思考
/my
请求为什么没有经过Spring的拦截器?
那么我们就要考虑一下DispatcherServlet
类是怎么注册到容器中的
我们需要分析下和DispatcherServlet
有关的自动配置类DispatcherServletAutoConfiguration
-
它下面有一个配置类
DispatcherServletConfiguration
,向容器中注册了DispatcherServlet
,并将属性绑定到WebMvcProperties
,点进去可以看到对应的配置文件配置项是spring.mvc
-
然后这里还有一个配置类
DispatcherServletRegistrationConfiguration
,它里面有一个方法dispatcherServletRegistration()
,这里就和我们上面第二节的作用是一样的,使用RegistrationBean把DispatcherServlet这个类当作Servlet组件注册到容器中
了解了上述原理之外,我们还需要了解一个原则,
精确优选原则
:如果一个请求能被两个Servlet处理,那么我们先选匹配精确度高的那个
这就解释了为什么,我们自定义的Servlet对应的请求没有被我们系统中配置的拦截器拦截,因为他直接走了tomcat,没有走Spring默认配置的DispatcherServlet
类下的doDispatch()
方法,我们拦截器的前置和后置等操作都在这个方法中进行
如有错误,欢迎指正!!!