1.web中的三大组件
Servlet,Filter,Listener。
1.1 Servlet
主要用来在业务处理之前进行控制,url传来之后,就对其进行处理,处理完成,返回或转向到某一自己指定的页面,可以向用户生成响应。
1.2 Filter
过滤器(Filter), 可以理解一个一种特殊Servlet,主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理,是一个典型的处理链,过滤请求,无法向用户生成响应。在 Servlet 前执行的。用于拦截和处理 HTTP 请求和响应,可用于身份认证、授权、日志记录和设置字符集(CharacterEncodingFilter)等场景。
1.3 Listener
监听器用于监听web应用中某些对象、信息的创建、销毁、增加,修改,删除等动作的发生,然后作出相应的响应处理。
常用监听器
- 监听session属性的增加、移除以及属性值改变的HttpSessionAttributeListener
- 监听web上下文的初始化(服务器已准备好接收请求)与销毁的ServletContextListener
- 监听web上下文属性的增加、删除、属性值变化的ServletContextAttributeListener
- 监听request的创建与销毁的ServletRequestListener
- 监听request的属性的增加、删除、属性值变化的ServletRequestAttributeListener
- 在线用户数统计的监听器HttpSessionListener
1.4 Interceptor
拦截器(Interceptor),和Servlet无关,由Spring框架实现。可用于身份认证、授权、日志记录、预先设置数据以及统计方法的执行效率等。
- 拦截器是基于java的反射机制的,而过滤器是基于函数回调。
- 拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
- 拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
- 拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
- 在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
- 拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
- 拦截器(Interceptor):它依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上,基于Java的反射机制,属于面向切面编程(AOP)的一种运用,就是在service或者一个方法前,调用一个方法,或者在方法后,调用一个方法。
Spring 中主要的拦截器有:
- HandlerInterceptor
- MethodInterceptor
HandlerInterceptor拦截器:
HandlerInterceptor 类似 Filter,拦截的是请求地址 ,但提供更精细的的控制能力,必须过DispatcherServlet 的请求才会被拦截。
@Configuration
@Slf4j
public class MyHandlerInterceptorConfig implements WebMvcConfigurer {
private static final Logger log = LoggerFactory.getLogger(MyHandlerInterceptorConfig.class);
@Override
public void addInterceptors(InterceptorRegistry registry) {
List<String> patterns = new ArrayList<>();
patterns.add("/**");
registry.addInterceptor(new MyHandlerInterceptor())
.addPathPatterns(patterns) // 需要拦截的请求
.excludePathPatterns(); // 不需要拦截的请求
}
public class MyHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("这是MyHandlerInterceptor.preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("这是MyHandlerInterceptor.postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("这是MyHandlerInterceptor.afterCompletion");
}
}
}
MethodInterceptor拦截器:
MethodInterceptor 是 AOP 中的拦截器,它拦截的目标是方法,可以不是 Controller 中的方法。
//第一步:新建一个Bean
@Service("aService")
public class AService {
BService bService;
public String aCallB() {
String bResult = bService == null ? "bService is null" : bService.bCallBaidu();
return "这是a;b返回:" + bResult;
}
}
//第二步:新建代理类
@Configuration
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("进入拦截,方法执行前,拦截方法是:" + methodInvocation.getMethod().getName());
Object result = methodInvocation.proceed();
System.out.println("方法执行后");
return result;
}
}
// 第三步:配置代理类和Bean
@Configuration
public class MyMethodInterceptorConfig {
@Bean
public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
// 使用BeanNameAutoProxyCreator来创建代理
BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
// 指定一组需要自动代理的Bean名称
beanNameAutoProxyCreator.setBeanNames("aService");
//设置拦截器名称,这些拦截器是有先后顺序的
beanNameAutoProxyCreator.setInterceptorNames("myMethodInterceptor");
return beanNameAutoProxyCreator;
}
}
//第四步: 测试调用Bean
{
@Autowired
AService aService;
@PostConstruct
public void init(){
aService.aCallB();
}
}
只有调用了bean才能触发拦截器:
2.过滤器和拦截器区别:
Filter | Interceptor | Summary |
Filter 接口定义在 javax.servlet 包中 | 接口 HandlerInterceptor 定义在org.springframework.web.servlet 包中 | |
Filter 定义在 web.xml 中 | ||
Filter在只在 Servlet 前后起作用。Filters 通常将 请求和响应(request/response) 当做黑盒子,Filter 通常不考虑servlet 的实现。 | 拦截器能够深入到方法前后、异常抛出前后等,因此拦截器的使用具有更大的弹性。允许用户介入(hook into)请求的生命周期,在请求过程中获取信息,Interceptor 通常和请求更加耦合。 | 在Spring构架的程序中,要优先使用拦截器。几乎所有 Filter 能够做的事情, interceptor 都能够轻松的实现 |
Filter 是 Servlet 规范规定的。 | 而拦截器既可以用于Web程序,也可以用于Application、Swing程序中。 | 使用范围不同 |
Filter 是在 Servlet 规范中定义的,是 Servlet 容器支持的。 | 而拦截器是在 Spring容器内的,是Spring框架支持的。 | 规范不同 |
Filter 不能够使用 Spring 容器资源 | 拦截器是一个Spring的组件,归Spring管理,配置在Spring文件中,因此能使用Spring里的任何资源、对象,例如 Service对象、数据源、事务管理等,通过IoC注入到拦截器即可 | Spring 中使用 interceptor 更容易 |
Filter 是被 Server(like Tomcat) 调用 | Interceptor 是被 Spring 调用 | 因此 Filter总是优先于interceptor执行 |
3.Spring Boot下Servlet、Filter等注册方法:
- 使用@WebFilter、@WebServlet、@WebListener注解来标识类
- 使用FilterRegistrationBean、ServletRegistrationBean来对Filter、Servlet进行自定义注册
- 使用@Bean来自动添加,添加后默认的过滤路径为 /*
2.1 @WebFilter或@WebServlet方式
- 可以指定拦截规则比如:
/*
,但无法指定过滤器的顺序 - @WebFilter注解要想生效必须在启动类上加上@ServletComponentScan注解
- Servlet3.0中,监听器的配置可以直接在代码中通过@WebListener
注解来完成
@WebFilter:
/**
* @description @WebFilter 注解要想生效必须在启动类上加上@ServletComponentScan注解
* 拦截规则是 /*,但无法制定过滤器的顺序
**/
@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
filterChain.doFilter(servletRequest,servletResponse);
}
}
@WebServlet:
@WebServlet
public class MyServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
@WebServlet
public class MyHttpServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
2.2 @Bean方式
- 可以指定优先级顺序,但拦截规则只能是
/*
@Configuration
@Order(-1)
public class BeanFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
filterChain.doFilter(servletRequest,servletResponse);
}
}
2.3 FilterRegistrationBean方式(推荐)
public FilterRegistrationBean<MyFilter> filterRegistrationBean() {
FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();
// 设置自己的过滤器
registrationBean.setFilter(new MyFilter());
// 设置自定义的拦截规则
registrationBean.addUrlPatterns("/*");
// 设置拦截器的顺序
registrationBean.setOrder(1);
// 是否启用
registrationBean.setEnabled(true);
return registrationBean;
}
@Bean
public ServletRegistrationBean<MyHttpServlet> servletRegistrationBean() {
ServletRegistrationBean<MyHttpServlet> registrationBean = new FilterRegistrationBean<>();
registrationBean.setServlet(new MyHttpServlet());
// 设置自定义的拦截规则
registrationBean.addUrlMappings("/**");
// 设置拦截器的顺序
registrationBean.setOrder(1);
// 是否启用
registrationBean.setEnabled(true);
return registrationBean;
}
参考:
Springboot过滤器注册的三种方式_springboot 注册过滤器-CSDN博客
SpringBoot配置Servlet的两种方式_springbootjspviewservletconfig-CSDN博客