目录
Spring 过滤器 拦截器 监听器 Aop
1. 过滤器
1. 简介
过滤器Filter用于对数据进行过滤和预处理
过滤器只能在请求前后使用
依赖于servlet容器 基于函数回调实现 其生命周期由servlet容器管理
过滤器只能初始化一次 且销毁只发生在服务停止或重新发布 即程序启动调用filter的init()有且一次 或有且一次当程序停止时调用filter的destroy() 调用doFilter()只在符合条件下执行
无法获取ioc容器中的bean
2. 使用场景
2.1 敏感数据过滤
2.2 URL层面的权限验证
2.3 设置编码格式
2.4 压缩响应信息、预处理请求信息等等...
3. 使用方式
3.1 @WebFilter注解修饰类 + 该类实现Filter接口 + 类重写doFilter方法(可选重写init和destroy方法) + 启动类@ServletComponentScan + (可选)Order(过滤器执行顺序序号)
3.2 @WebFilter注解修饰类 + 该类实现Filter接口 + 类重写doFilter方法(可选重写init和destroy方法) + @Configuration修饰的配置类并通过FilterRegistrationBean注册Filter
3.3 该类实现Filter接口 + 类重写doFilter方法(可选重写init和destroy方法) + @Configuration修饰的配置类并通过FilterRegistrationBean注册Filter
3.4 @Component注解修饰类 + 该类实现Filter接口 + 类重写doFilter方法(可选重写init和destroy方法) + (可选)Order(过滤器执行顺序序号)
package com.ntt.web.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
// 方式1 @WebFilter + 实现Filter接口 + 启动类 @ServletComponentScan 拦截*
@WebFilter(filterName = "filter1", urlPatterns = {"/*"})
@Slf4j
@Order(1)
class Filter1 implements Filter
{
@Override
public void init(FilterConfig fg) throws ServletException
{
log.info("filter1-init");
}
@Override
public void destroy()
{
log.info("filter1-destroy");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
log.info("filter1-start");
// 可对请求前后数据进行预处理
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
chain.doFilter(req, res); // 可添加响应逻辑是否对该URI访问资源放行或做其它处理
log.info("filter1-end");
}
}
// 方式2 @WebFilter + 实现Filter接口 + @Configure修饰的配置类并通过FilterRegistrationBean注册Filter
//@WebFilter // 为避免多次注册 当启动类使用@ServletComponentScan修饰 建议屏蔽该注解
@Slf4j
class Filter2 implements Filter
{
@Override
public void init(FilterConfig fg) throws ServletException
{
log.info("filter2-init");
}
@Override
public void destroy()
{
log.info("filter2-destroy");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
log.info("filter2-start");
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
chain.doFilter(req, res);
log.info("filter2-end");
}
}
// 方式3 实现Filter接口 +类重写doFilter方法(可选重写init和destroy方法) + @Configure修饰的配置类并通过FilterRegistrationBean注册Filter
@Slf4j
class Filter3 implements Filter
{
@Override
public void init(FilterConfig fg) throws ServletException
{
log.info("filter3-init");
}
@Override
public void destroy()
{
log.info("filter3-destroy");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
log.info("filter3-start");
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
chain.doFilter(req, res);
log.info("filter3-end");
}
}
// 方式4 @Component + 实现Filter接口 不指定过滤url 默认/*
@Component
@Slf4j
@Order(4)
class Filter4 implements Filter {
@Override
public void init(FilterConfig fg) throws ServletException
{
log.info("filter4-init");
}
@Override
public void destroy()
{
log.info("filter4-destroy");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
log.info("filter4-start");
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
chain.doFilter(req, res);
log.info("filter4-end");
}
}
// 配置类
@Configuration
public class FilterConfig{
@Bean
public FilterRegistrationBean<Filter> Filter2()
{
FilterRegistrationBean<Filter> fb = new FilterRegistrationBean<>();
fb.setFilter(new Filter2());
fb.addUrlPatterns("/*");
fb.setName("filter2");
fb.setOrder(2);
return fb;
}
@Bean
public FilterRegistrationBean<Filter> Filter3()
{
FilterRegistrationBean<Filter> fb = new FilterRegistrationBean<>();
fb.setFilter(new Filter3());
fb.addUrlPatterns("/*");
fb.setName("filter3");
fb.setOrder(3);
return fb;
}
}
package com.ntt.web;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Configuration;
// 启动类
@SpringBootApplication
@Configuration
@ServletComponentScan
public class CmsApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(CmsApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(CmsApplication.class);
}
}
package com.ntt.web.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
// 控制器类
@RestController
@RequestMapping("/api/v1")
@Slf4j
public class TestController {
@GetMapping(value = "/filter")
public void filter()
{
log.info("调用地址:/filter");
}
@GetMapping(value = "/interceptor")
public void interceptor()
{
log.info("调用地址:/interceptor");
}
@GetMapping(value = "/listener")
public void listener(HttpServletRequest req)
{
Integer count = (Integer) req.getSession().getServletContext().getAttribute("count");
log.info("调用地址:/listener;count:{}", count);
}
@GetMapping(value = "/aop")
public Object aop() {
log.info("调用地址:/aop");
// Integer err = 1 /0; // 抛出异常触发通知afterThrowing
return "aop";
}
@GetMapping(value = "/")
public void get()
{
log.info("调用地址:/");
}
}
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.6)
2024-10-09 14:53:42.960 INFO 29568 --- [ main] com.ntt.web.CmsApplication : Starting CmsApplication using Java
2024-10-09 14:53:42.962 INFO 29568 --- [ main] com.ntt.web.CmsApplication : No active profile set, falling back to default profiles: default
2024-10-09 14:53:44.213 INFO 29568 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 9999 (http)
2024-10-09 14:53:44.229 INFO 29568 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2024-10-09 14:53:44.229 INFO 29568 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.54]
2024-10-09 14:53:44.231 INFO 29568 --- [ main] o.a.catalina.core.AprLifecycleListener : Loaded Apache Tomcat Native library [1.2.32] using APR version [1.7.0]
2024-10-09 14:53:44.341 INFO 29568 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2024-10-09 14:53:44.341 INFO 29568 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1338 ms
2024-10-09 14:53:44.461 INFO 29568 --- [ main] com.ntt.web.config.Filter1 : filter1-init
2024-10-09 14:53:44.462 INFO 29568 --- [ main] com.ntt.web.config.Filter2 : filter2-init
2024-10-09 14:53:44.462 INFO 29568 --- [ main] com.ntt.web.config.Filter3 : filter3-init
2024-10-09 14:53:44.462 INFO 29568 --- [ main] com.ntt.web.config.Filter4 : filter4-init
_ _ |_ _ _|_. ___ _ | _
| | |\/|_)(_| | |_\ |_)||_|_\
/ |
3.5.1
2024-10-09 14:53:48.262 INFO 29568 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 9999 (http) with context path ''
2024-10-09 14:53:48.272 INFO 29568 --- [ main] com.ntt.web.CmsApplication : Started CmsApplication in 5.718 seconds (JVM running for 8.262)
2024-10-09 14:53:48.743 INFO 29568 --- [nio-9999-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2024-10-09 14:53:48.743 INFO 29568 --- [nio-9999-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2024-10-09 14:53:48.744 INFO 29568 --- [nio-9999-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
2024-10-09 14:53:48.750 INFO 29568 --- [nio-9999-exec-1] com.ntt.web.config.Filter2 : filter2-start
2024-10-09 14:53:48.750 INFO 29568 --- [nio-9999-exec-1] com.ntt.web.config.Filter3 : filter3-start
2024-10-09 14:53:48.750 INFO 29568 --- [nio-9999-exec-1] com.ntt.web.config.Filter4 : filter4-start
2024-10-09 14:53:48.750 INFO 29568 --- [nio-9999-exec-1] com.ntt.web.config.Filter1 : filter1-start
2024-10-09 14:53:48.764 INFO 29568 --- [nio-9999-exec-1] com.ntt.web.controller.TestController : 调用地址:/filter
2024-10-09 14:53:48.780 INFO 29568 --- [nio-9999-exec-1] com.ntt.web.config.Filter1 : filter1-end
2024-10-09 14:53:48.781 INFO 29568 --- [nio-9999-exec-1] com.ntt.web.config.Filter4 : filter4-end
2024-10-09 14:53:48.781 INFO 29568 --- [nio-9999-exec-1] com.ntt.web.config.Filter3 : filter3-end
2024-10-09 14:53:48.781 INFO 29568 --- [nio-9999-exec-1] com.ntt.web.config.Filter2 : filter2-end
2024-10-09 14:55:57.211 INFO 29568 --- [ionShutdownHook] com.ntt.web.config.Filter1 : filter1-destroy
2024-10-09 14:55:57.211 INFO 29568 --- [ionShutdownHook] com.ntt.web.config.Filter2 : filter2-destroy
2024-10-09 14:55:57.212 INFO 29568 --- [ionShutdownHook] com.ntt.web.config.Filter3 : filter3-destroy
2024-10-09 14:55:57.212 INFO 29568 --- [ionShutdownHook] com.ntt.web.config.Filter4 : filter4-destroy
2024-10-09 14:55:57.229 INFO 29568 --- [ionShutdownHook] com.alibaba.druid.pool.DruidDataSource : {dataSource-0} closing ...
2. 拦截器
1.简介
拦截器interceptor依赖于Spring容器 是aop面向切面编程的一种方式 拦截处理器的执行 执行顺序晚于过滤器 属于全局行为 功能近似与过滤器
HandlerInterceptor接口相关方法
preHandle: 处理器执行前执行 返回false则直接执行afterCompletion方法 多个执行顺序为顺序
postHandle: 处理器执行后 视图渲染前执行 若异常 则执行执行afterCompletion方法 多个执行顺序为逆序
afterCompletion: 视图渲染后执行 最后均会被执行该方法 多个执行顺序为逆序
过滤器和拦截器执行流程
filter->interceptor.preHandle->handler->interceptor.postHandle->interceptor.afterCompletion->filter
2.使用场景
2.1 登录或权限验证
2.2 日志额外信息记录打印
2.3 性能监控
2.4 用户行为记录等等...
3.使用方式
3.1 实现HandlerInterceptor接口 + @Configuration修饰的配置类重写addInterceptors方法 注册拦截器
3.2 实现HandlerInterceptor接口 + @Configuration修饰的配置类 + @Bean MappedInterceptor方法 注册拦截器 + (可选) @Order指定顺序
package com.ntt.web.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.handler.MappedInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// 方式1 实现HandlerInterceptor接口 + @Configuration修饰的配置类重写addInterceptors方法 注册拦截器
@Slf4j
class Interceptor1 implements HandlerInterceptor
{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
log.info("Interceptor1-preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception
{
log.info("Interceptor1-postHandle");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
log.info("Interceptor1-afterCompletion");
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
@Slf4j
class Interceptor2 implements HandlerInterceptor, Ordered
{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
log.info("Interceptor2-preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception
{
log.info("Interceptor2-postHandle");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
log.info("Interceptor2-afterCompletion");
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
@Override
public int getOrder() {
return 2;
}
}
// 方式2 实现HandlerInterceptor接口 + @Configuration修饰的配置类 + @Bean MappedInterceptor方法 注册拦截器 + (可选) @Order指定顺序
@Slf4j
class Interceptor3 implements HandlerInterceptor
{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
log.info("Interceptor3-preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception
{
log.info("Interceptor3-postHandle");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
log.info("Interceptor3-afterCompletion");
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
//
@Configuration
public class InterceptorConfig implements WebMvcConfigurer
{
private final String[] allowUrls = {"/api/v1/interceptor"};
private final String[] banUrls = {"/api/v1/filter"};
// @Bean
// @Order(3)
// public MappedInterceptor interceptor3(){
// return new MappedInterceptor(allowUrls, banUrls, new Interceptor3());
// }
@Override
public void addInterceptors(InterceptorRegistry registry)
{
// 添加拦截器
registry.addInterceptor(new Interceptor1())
.addPathPatterns(allowUrls)
.excludePathPatterns(banUrls)
.order(1);
registry.addInterceptor(new Interceptor2())
.addPathPatterns(allowUrls)
.excludePathPatterns(banUrls)
.order(2);
registry.addInterceptor(new Interceptor3())
.addPathPatterns(allowUrls)
.excludePathPatterns(banUrls)
.order(3);
}
}
2024-10-09 16:20:25.351 INFO 6480 --- [nio-9999-exec-1] com.ntt.web.config.Interceptor1 : Interceptor1-preHandle
2024-10-09 16:20:25.351 INFO 6480 --- [nio-9999-exec-1] com.ntt.web.config.Interceptor2 : Interceptor2-preHandle
2024-10-09 16:20:25.351 INFO 6480 --- [nio-9999-exec-1] com.ntt.web.config.Interceptor3 : Interceptor3-preHandle
2024-10-09 16:20:25.358 INFO 6480 --- [nio-9999-exec-1] com.ntt.web.controller.TestController : 调用地址:/interceptor
2024-10-09 16:20:25.373 INFO 6480 --- [nio-9999-exec-1] com.ntt.web.config.Interceptor3 : Interceptor3-postHandle
2024-10-09 16:20:25.373 INFO 6480 --- [nio-9999-exec-1] com.ntt.web.config.Interceptor2 : Interceptor2-postHandle
2024-10-09 16:20:25.374 INFO 6480 --- [nio-9999-exec-1] com.ntt.web.config.Interceptor1 : Interceptor1-postHandle
2024-10-09 16:20:25.374 INFO 6480 --- [nio-9999-exec-1] com.ntt.web.config.Interceptor3 : Interceptor3-afterCompletion
2024-10-09 16:20:25.374 INFO 6480 --- [nio-9999-exec-1] com.ntt.web.config.Interceptor2 : Interceptor2-afterCompletion
2024-10-09 16:20:25.374 INFO 6480 --- [nio-9999-exec-1] com.ntt.web.config.Interceptor1 : Interceptor1-afterCompletion
3.监听器
1. 简介
监听器是一种Servlet特殊类 用于监听web中的相关对象创建、销毁、修改等事件操作 主要是ServletContext HttpSession ServletRequest 监听
2. 使用场景
2.1 监听ServletContext 关于应用web初始化的信息 缓存数据信息
2.2 监听HttpSession 关于用户会话信息
2.3 监听SerVletRequest 关于用户的请求信息 等...
3. 使用方法
3.1 实现ServletContextListener接口 + [@WebListener修饰类 + 启动类@ServletComponentScan] 或 @Component修饰类 或 @Configuration配置类 & @Bean 修饰ServletListenerRegistrationBean方法 注册监听器
3.2 实现HttpSessionListener接口 + [@WebListener修饰类 + 启动类@ServletComponentScan] 或 @Component修饰类 或 @Configuration配置类 & @Bean 修饰ServletListenerRegistrationBean方法 注册监听器
3.3 实现ServletRequestListener接口 + [@WebListener修饰类 + 启动类@ServletComponentScan] 或 @Component修饰类 或 @Configuration配置类 & @Bean 修饰ServletListenerRegistrationBean方法 注册监听器
package com.ntt.web.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
// 方式1 @Component修饰类 + 实现对应listener接口
@Component
@Slf4j
class Listener1 implements ServletContextListener
{
@Override
public void contextInitialized(ServletContextEvent sce)
{
log.info("ServletContextListener-start");
}
@Override
public void contextDestroyed(ServletContextEvent sce)
{
log.info("ServletContextListener-end");
}
}
// 方式2 @WebListener修饰类 + 实现对应listener接口 + @ServletComponentScan修饰启动类
@WebListener
@Slf4j
class Listener2 implements HttpSessionListener
{
private static Integer count = 0;
@Override
public synchronized void sessionCreated(HttpSessionEvent se)
{
count ++;
HttpSession sn = se.getSession();
sn.setMaxInactiveInterval(60);
sn.getServletContext().setAttribute("count", count);
log.info("HttpSessionListener-start");
}
@Override
public synchronized void sessionDestroyed(HttpSessionEvent se)
{
count --;
HttpSession sn = se.getSession();
sn.setMaxInactiveInterval(60);
sn.getServletContext().setAttribute("count", count);
log.info("HttpSessionListener-end");
}
}
// 方式3 实现对应listener接口 + @Configuration配置类 & @Bean 修饰ServletListenerRegistrationBean方法 注册监听器
@Slf4j
class Listener3 implements ServletRequestListener
{
@Override
public void requestDestroyed (ServletRequestEvent sre) {
log.info("ServletRequestListener-start");
}
@Override
public void requestInitialized (ServletRequestEvent sre) {
log.info("ServletRequestListener-end");
}
}
@Configuration
public class ListenerConfig {
// @Bean // 实际测试采用该方式注册
// public ServletListenerRegistrationBean<Listener2> Listener2(){
// ServletListenerRegistrationBean<Listener2> rb = new ServletListenerRegistrationBean<>();
// rb.setListener(new Listener2());
//// rb.setOrder(1);
// return rb;
// }
@Bean
public ServletListenerRegistrationBean<Listener3> Listener3(){
ServletListenerRegistrationBean<Listener3> rb = new ServletListenerRegistrationBean<>();
rb.setListener(new Listener3());
// rb.setOrder(2);
return rb;
}
}
2024-10-10 16:35:13.414 INFO 41960 --- [ main] com.ntt.web.config.Listener1 : ServletContextListener-start
2024-10-10 16:35:17.113 INFO 41960 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 9999 (http) with context path ''
2024-10-10 16:35:17.123 INFO 41960 --- [ main] com.ntt.web.CmsApplication : Started CmsApplication in 5.375 seconds (JVM running for 7.518)
2024-10-10 16:35:17.951 INFO 41960 --- [nio-9999-exec-1] com.ntt.web.config.Listener3 : ServletRequestListener-end
2024-10-10 16:35:17.957 INFO 41960 --- [nio-9999-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2024-10-10 16:35:17.957 INFO 41960 --- [nio-9999-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2024-10-10 16:35:17.958 INFO 41960 --- [nio-9999-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
2024-10-10 16:35:17.979 INFO 41960 --- [nio-9999-exec-1] com.ntt.web.config.Listener2 : HttpSessionListener-start
2024-10-10 16:35:17.980 INFO 41960 --- [nio-9999-exec-1] com.ntt.web.controller.TestController : 调用地址:/listener;count:1
2024-10-10 16:35:17.997 INFO 41960 --- [nio-9999-exec-1] com.ntt.web.config.Listener3 : ServletRequestListener-start
2024-10-10 16:35:47.376 INFO 41960 --- [ionShutdownHook] com.ntt.web.config.Listener2 : HttpSessionListener-end
2024-10-10 16:35:47.376 INFO 41960 --- [ionShutdownHook] com.ntt.web.config.Listener1 : ServletContextListener-end
2024-10-10 16:35:47.394 INFO 41960 --- [ionShutdownHook] com.alibaba.druid.pool.DruidDataSource : {dataSource-0} closing ...
4.Aop
1. 简介
AOP(Aspect-Oriented Programming面向切面编程)是Spring框架的一个核心功能 它允许开发者在不修改业务逻辑代码的情况下 通过定义切面(Aspect)和通知(Advice)来增强代码的功能
Spring AOP 主要用于日志记录 权限检查 事务管理等跨越多个请求的处理
Spring AOP 的核心概念包括
切面(Aspect):切面是通知和切点的结合 它定义了何时何地以及如何应用通知
通知(Advice):通知是切面的一个具体实现 它定义了在切点处需要执行的额外逻辑
Spring 支持以下类型的通知:
前置通知(Before):在切点之前执行
后置通知(After):在切点之后执行 无论方法是否成功
返回通知(After Returning):在方法成功返回后执行
异常通知(After Throwing):在方法抛出异常后执行
环绕通知(Around):包围切点 可以在方法执行前后执行自定义逻辑
切点(Pointcut):切点是应用程序中的一个或一组特定位置 如方法的执行或异常的抛出 切点表达式用于匹配这些位置
连接点(Joinpoint):连接点是应用程序执行过程中的一个特定点 如方法调用或字段访问 Spring AOP 仅支持方法执行的连接点
目标对象(Target Object):被代理的对象
代理(Proxy):代理对象是AOP框架创建的对象 它包含目标对象的引用 并在调用目标对象的方法时应用切面
织入(Weaving):织入是将切面应用到目标对象并创建代理对象的过程 织入可以在编译时 类加载时或运行时进行
2. 使用场景
2.1 日志记录
2.2 权限检查
2.3 事务管理
2.4 性能监控
2.5 异常处理
2.6 数据校验等等...
3. 使用方法
流程步骤
定义切面:创建一个类 使用 @Aspect 注解标记它作为切面
定义切点:使用 @Pointcut 注解定义切点表达式
定义通知:在切面类中定义通知方法 并使用相应的注解(如 @Before、@After、@AfterReturning、@AfterThrowing、@Around)标记它们
启用AOP:在配置类上使用 @EnableAspectJAutoProxy 注解启用AOP (原生spring需要在配置文件配置 springboot默认启用)
实现方式
jdk动态代理:在运行时使用 Java 的 Proxy 类和 InvocationHandler 接口生成代理对象 JDK 动态代理只能代理实现了接口的类 因为它依赖于接口的实现
CGLIB代理: 使用 CGLIB 库(Code Generation Library)在运行时动态生成被代理类的子类来创建代理对象 CGLIB 代理不要求被代理的类实现任何接口 因此它可以代理没有实现接口的类
相关注解解释
@Aspect:将一个 java 类定义为切面类
@Pointcut:定义一个切入点 可以是一个规则表达式 比如下例中某个 package 下的所有函数 也可以是一个注解等
@Before:在切入点开始处切入内容
@After:在切入点结尾处切入内容 无论是否有异常 都会执行 类似于finally
@AfterReturning:在切入点 return 内容之后处理逻辑 只有执行成功会执行 异常不会
@Around:在切入点前后切入内容 并自己控制何时执行切入点自身的内容 原则上可以替代@Before和@After
@AfterThrowing:用来处理当切入内容部分抛出异常之后的处理逻辑
@Order(100):AOP 切面执行顺序 @Before 数值越小越先执行 @After 和 @AfterReturning 数值越大越先执行
切点表达式
execution(<方法的修饰符><方法的返回类型><包.类.方法名(参数)><异常>)
修饰符(可省略): public private protected static 或者 * 可使用&&指定多个
返回值(不可省略): void String *
包|类|方法名: 方法名不可省略 可以是详细的包 类名 方法名 或者使用*通配符替代
*:匹配任意字符 匹配一个(包 类 方法 方法参数)
..: 匹配任意字符 匹配多个
+: 类型匹配 匹配指定类名
参数: ()无参 (int)一个参数 (..)任意参数
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.5.6</version>
</dependency>
package com.ntt.web.aop;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect // 定义切面
@Component
@Slf4j
public class TestAspect
{
// 定义切点
@Pointcut("execution(* com.ntt.web.controller.TestController.*(..))")
public void targetCut(){}
// 实现通知
@Before("targetCut()")
public void before()
{
log.info("before");
}
@After("targetCut()")
public void after()
{
log.info("after");
}
//@AfterReturning(value = "targetCut()", returning = "res")
//public void afterReturn(JoinPoint jp, Object res)
@AfterReturning("targetCut()")
public void afterReturn()
{
log.info("afterReturn");
}
//@AfterThrowing(value = "targetCut()", throwing = "err")
//public void afterThrowing(JoinPoint jp, Throwable err)
@AfterThrowing("targetCut()")
public void afterThrowing()
{
log.info("afterThrowing");
}
@Around("targetCut()")
public Object around(ProceedingJoinPoint pjp)
{
Object oj = null;
log.info("around-begin");
try{
// 目标业务处理
oj = pjp.proceed();
}catch (Throwable e){
e.printStackTrace();
}
log.info("around-end");
return oj;
}
}
2024-10-11 17:23:11.646 INFO 37312 --- [nio-9999-exec-2] com.ntt.web.aop.TestAspect : around-begin
2024-10-11 17:23:11.646 INFO 37312 --- [nio-9999-exec-2] com.ntt.web.aop.TestAspect : before
2024-10-11 17:23:11.656 INFO 37312 --- [nio-9999-exec-2] com.ntt.web.controller.TestController : 调用地址:/aop
2024-10-11 17:23:11.657 INFO 37312 --- [nio-9999-exec-2] com.ntt.web.aop.TestAspect : afterThrowing
2024-10-11 17:23:11.657 INFO 37312 --- [nio-9999-exec-2] com.ntt.web.aop.TestAspect : after
2024-10-11 17:23:11.659 INFO 37312 --- [nio-9999-exec-2] com.ntt.web.aop.TestAspect : around-end
2024-10-11 17:24:46.781 INFO 37272 --- [nio-9999-exec-1] com.ntt.web.aop.TestAspect : around-begin
2024-10-11 17:24:46.781 INFO 37272 --- [nio-9999-exec-1] com.ntt.web.aop.TestAspect : before
2024-10-11 17:24:46.791 INFO 37272 --- [nio-9999-exec-1] com.ntt.web.controller.TestController : 调用地址:/aop
2024-10-11 17:24:46.792 INFO 37272 --- [nio-9999-exec-1] com.ntt.web.aop.TestAspect : afterReturn
2024-10-11 17:24:46.792 INFO 37272 --- [nio-9999-exec-1] com.ntt.web.aop.TestAspect : after
2024-10-11 17:24:46.792 INFO 37272 --- [nio-9999-exec-1] com.ntt.web.aop.TestAspect : around-end
5. 参考文档
[1] https://blog.csdn.net/qq_43842093/article/details/135578271
[2] https://segmentfault.com/a/1190000021823564#item-4
[3] https://blog.csdn.net/houpeibin2012/article/details/104449730
[4] https://www.baeldung.com/spring-aop
标签:INFO,web,---,拦截器,10,Spring,2024,监听器,com From: https://www.cnblogs.com/fsh19991001/p/18458953