SpringBoot基于注解切面监听事件
Posted 一点点
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot基于注解切面监听事件相关的知识,希望对你有一定的参考价值。
创建监听器三步骤:
1、事件(event)可以封装和传递监听器中要处理的参数,如对象或字符串,并作为监听器中监听的目标。
2、监听器(listener)具体根据事件发生的业务处理模块,这里可以接收处理事件中封装的对象或字符串。
3、事件发布者(publisher)事件发生的触发者。
代码展示:
pom.xml
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>4.6.8</version> </dependency>
第一步:
定义一个事件,需要继承spring的ApplicationEvent
package top.xzhand.event; import org.springframework.context.ApplicationEvent; /** * 定义一个事件,需要继承spring的ApplicationEvent */ public class LogEvent extends ApplicationEvent { public LogEvent(Object source) { super(source); } }
第二步:
定义切面,发布事件
@Component
@Aspect
这两个注解必须添加
package top.xzhand.event.aspect; import com.alibaba.fastjson.JSON; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; import top.xzhand.event.LogEvent; import top.xzhand.po.RequestLog; import org.aspectj.lang.JoinPoint; import top.xzhand.util.LogUtil; import java.util.Date; /** * 切面发布 */ @Component @Aspect public class LogAspect { public static final ThreadLocal<RequestLog> THREAD_LOCAL = new ThreadLocal<>(); @Autowired private ApplicationContext applicationContext; @Pointcut("@annotation(top.xzhand.event.common.Log)") public void logAspect() { } @Before(value = "logAspect()") public void before(JoinPoint point) throws Throwable { RequestLog requestLog = new RequestLog(); requestLog.setCreateAt(new Date());//开始时间 Environment environment = applicationContext.getEnvironment(); String appName = environment.getProperty("spring.application.name"); // sysLog.setCreateName(createName); THREAD_LOCAL.set(LogUtil.getSysLog(point,requestLog)); System.out.println("进入切面:"+JSON.toJSONString(requestLog)); } @AfterReturning(returning = "rvt", pointcut = "logAspect()") public void afterReturning(JoinPoint point, Object rvt) throws Throwable { RequestLog sysLog = get(); if (rvt != null) { sysLog.setResponseResult(LogUtil.getText(JSON.toJSONString(rvt))); } else { sysLog.setResponseResult(null); } publishEvent(sysLog); System.out.println("切面监听事件发布成功:"+JSON.toJSONString(sysLog)); } private void publishEvent(RequestLog sysLog) { applicationContext.publishEvent(new LogEvent(sysLog)); THREAD_LOCAL.remove(); } @AfterThrowing(pointcut = "logAspect()", throwing = "e") public void afterThrowing(Throwable e) { RequestLog sysLog = get(); publishEvent(sysLog); } private RequestLog get() { RequestLog sysLog = THREAD_LOCAL.get(); if (sysLog == null) { return new RequestLog(); } return sysLog; } }
定义切入点注解
package top.xzhand.event.common; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 方法级别 日志 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented public @interface Log { String value() default ""; }
相关实体类,mapper,service等忽略,可自己生成!
package top.xzhand.po; import java.util.Date; public class RequestLog { private Integer id; private String requestUrl; private String requestArgs; private String ipUrl; private String message; private String responseResult; private Date createAt; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getRequestUrl() { return requestUrl; } public void setRequestUrl(String requestUrl) { this.requestUrl = requestUrl == null ? null : requestUrl.trim(); } public String getRequestArgs() { return requestArgs; } public void setRequestArgs(String requestArgs) { this.requestArgs = requestArgs == null ? null : requestArgs.trim(); } public String getIpUrl() { return ipUrl; } public void setIpUrl(String ipUrl) { this.ipUrl = ipUrl == null ? null : ipUrl.trim(); } public String getMessage() { return message; } public void setMessage(String message) { this.message = message == null ? null : message.trim(); } public String getResponseResult() { return responseResult; } public void setResponseResult(String responseResult) { this.responseResult = responseResult == null ? null : responseResult.trim(); } public Date getCreateAt() { return createAt; } public void setCreateAt(Date createAt) { this.createAt = createAt; } }
package top.xzhand.util; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.URLUtil; import lombok.experimental.UtilityClass; import org.aspectj.lang.JoinPoint; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import top.xzhand.event.common.Log; import top.xzhand.po.RequestLog; import javax.servlet.http.HttpServletRequest; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.Method; import java.util.Date; @UtilityClass // 方法变量 静态话,类final 私有构造器 public class LogUtil { public RequestLog getSysLog(JoinPoint point, RequestLog sysLog) { HttpServletRequest request = getRequest(); sysLog.setIpUrl(getIP(request)); sysLog.setRequestUrl(URLUtil.getPath(request.getRequestURI())); sysLog.setRequestArgs(request.getQueryString()); sysLog.setCreateAt(new Date()); return sysLog; } private HttpServletRequest getRequest() { return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); } private final String UNKNOWN = "unknown"; public String getIP(HttpServletRequest request) { String ip = request.getHeader("X-Requested-For"); if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getHeader("X-Forwarded-For"); } if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); } if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } return StrUtil.isBlank(ip) ? null : ip.split(",")[0]; } public String getText(String val) { return StrUtil.sub(val, 0, 65535); } /*** * 获取操作信息 * * @param point * @return */ public String getControllerMethodDescription(JoinPoint point) { try { // 获取连接点目标类名 String targetName = point.getTarget().getClass().getName(); // 获取连接点签名的方法名 String methodName = point.getSignature().getName(); // 获取连接点参数 Object[] args = point.getArgs(); // 根据连接点类的名字获取指定类 Class targetClass = Class.forName(targetName); // 获取类里面的方法 Method[] methods = targetClass.getMethods(); String description = ""; for (Method method : methods) { if (method.getName().equals(methodName)) { Class[] clazzs = method.getParameterTypes(); if (clazzs.length == args.length) { description = method.getAnnotation(Log.class).value(); break; } } } return description; } catch (Exception e) { return ""; } } /** * 获取堆栈信息 * * @param throwable * @return */ public String getStackTrace(Throwable throwable) { StringWriter sw = new StringWriter(); try (PrintWriter pw = new PrintWriter(sw)) { throwable.printStackTrace(pw); return getText(sw.toString()); } } }
package top.xzhand.event; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; import top.xzhand.po.RequestLog; /** * 事件发布 * */ @Component public class EventPublister { @Autowired private ApplicationContext applicationContext; // 事件发布方法 public void pushListener(RequestLog requsetLog) { applicationContext.publishEvent(new LogEvent(requsetLog)); } }
第三步:
自定义监听器处理业务
package top.xzhand.event; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; import top.xzhand.po.RequestLog; import top.xzhand.service.RequestLogService; /** * 自己定义的监听器需要实现ApplicationListener, * 同时泛型参数要加上自己要监听的事件Class名, * 在重写的方法onApplicationEvent中,添加自己的业务处理 */ @Component public class LogListerner implements ApplicationListener<LogEvent> { @Autowired private RequestLogService requestLogService; @Override public void onApplicationEvent(LogEvent logEvent) { RequestLog requestLog=(RequestLog) logEvent.getSource(); requestLogService.insertSelective(requestLog); } }
验证测试:
package top.xzhand.controller; import com.alibaba.fastjson.JSON; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import top.xzhand.event.EventPublister; import top.xzhand.event.common.Log; import top.xzhand.po.RequestLog; import top.xzhand.util.LogUtil; import javax.servlet.http.HttpServletRequest; import java.util.Date; /** * */ @Controller public class TestEventListenerController { @Autowired private EventPublister publisher; /** * 非注解形式监听事件 * @param request * @param arg */ @RequestMapping(value = "/test/logEvent1" ) public void testPublishEvent1(HttpServletRequest request,String arg ){ RequestLog requestLog=new RequestLog(); requestLog.setCreateAt(new Date()); requestLog.setRequestUrl(request.getContextPath()); requestLog.setIpUrl(LogUtil.getIP(request)); requestLog.setRequestArgs(request.getQueryString()); publisher.pushListener(requestLog); System.out.println(JSON.toJSONString(requestLog)); } /** * 基于注解的切面事件发布监听 * @param request * @param arg */ @Log @RequestMapping(value = "/test/logEvent2" ) public void testPublishEvent2(HttpServletRequest request,String arg ){ System.out.println("切面注解监听"); } }
日志成功记录
以上是关于SpringBoot基于注解切面监听事件的主要内容,如果未能解决你的问题,请参考以下文章