1.1 模拟事件发布监听
1.1.1 日志纪录类
@Data
public class OptDto {
private String requestIp; //操作IP
private String type ; //日志类型 LogType{ OPT:操作类型; EX:异常类型}
private String userName; //操作人
private String description; //操作描述
}
1.1.2 事件类,封装日志类
public class SysLogEvent extends ApplicationEvent {
public SysLogEvent( OptLogDTO optLogDTO) {
super( optLogDTO) ;
}
}
1.1.3 事件监听类
@Component
public class SysLogListener {
@Async//异步处理
@EventListener( SysLogEvent.class)
public void saveSysLog( SysLogEvent event) {
OptLogDTO sysLog = ( OptLogDTO) event.getSource( ) ;
long id = Thread.currentThread( ) .getId( ) ;
System.out.println( "监听到日志操作事件:" + sysLog + " 线程id:" + id ) ;
//将日志信息保存到数据库.. .
}
}
1.1.4 controller
@Autowired
private ApplicationContext applicationContext;
@GetMapping( "/getUser" )
public String getUser ( ) {
//构造操作日志信息
OptLogDTO logInfo = new OptLogDTO( ) ;
logInfo.setRequestIp( "127.0.0.1" ) ;
logInfo.setUserName( "admin" ) ;
logInfo.setType( "OPT" ) ;
logInfo.setDescription( "查询用户信息" ) ;
//构造事件对象
ApplicationEvent event = new SysLogEvent( logInfo) ;
//发布事件
applicationContext.publishEvent( event) ;
long id = Thread.currentThread( ) .getId( ) ;
System.out.println( "发布事件,线程id:" + id ) ;
return "OK" ;
}
1.1.5 启动类开启异步处理
@SpringBootApplication
@EnableAsync//启用异步处理
public class aadStarter {
public static void main( String[ ] args) {
SpringApplication.run( aadStarter.class,args) ;
}
}
1.1.6 流程
定义事件描述类,用于描述事件,定义日志事件继承ApplicationEvent封装事件描述类。 定义监听器SysLogListener,用于监听事件,监听到事件对事件进行处理 controller模拟事件发生,发布事件,由监听者监听并处理。
1.2 spring切面Aop
参考:Spring自定义注解的使用(实现切面
1.2.1 概念
切入点:对哪些注解进行操作 多个切面类在类上使用@Order定义切面类执行顺序 连接点:连接的是匹配规则后的具体方法
1.2.2 pom
< dependency>
< groupId> org.springframework.boot< /groupId>
< artifactId> spring-boot-starter-web< /artifactId>
< /dependency>
< dependency>
< groupId> org.springframework< /groupId>
< artifactId> spring-aspects< /artifactId>
< /dependency>
1.2.3 定义切面类
添加注解@Aspect 定义切点,对哪个注解进行处理,比如对常见的注解RequestMaping或者自定义注解处理
@Pointcut( "@annotation(com.itheima.pinda.log.annotation.SysLog)" )
public void sysLogAspect ( ) {
}
package org.example.Event;
import java.lang.annotation.*;
/**
* 操作日志注解
*
*/
@Target( ElementType.METHOD)
@Retention( RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
/**
* 描述
*
* @return { String}
*/
String value( ) default "" ;
}
1.2.4 通知类型测试
1.2.4.1 before
@Before( value = "mySysLogAspect()" )
public void doBefore( JoinPoint joinPoint) {
MethodSignature signature = ( MethodSignature) joinPoint.getSignature( ) ;
Class< ?> aClass = joinPoint.getTarget( ) .getClass( ) ;
Method method = signature.getMethod( ) ;
log.info( "before" ) ;
System.out.println( "before" + method.getName( ) + aClass.toString( )) ;
}
1.2.4.2 around
方法执行前后都可以执行 获取方法得到的参数,比如url上的参数,修改方法执行的结果。
@Around( value = "mySysLogAspect()" )
public Object doAround( ProceedingJoinPoint joinPoint) throws Throwable {
Object[ ] args = joinPoint.getArgs( ) ;
for( Object object: args) {
System.out.println( object.toString( )) ;
}
Object proceed = joinPoint.proceed( ) ;
if( proceed instanceof String) {
Object res = ( String) proceed + "加了一点东西" ;
return res;
}
return proceed;
}
1.2.4.4 afterReturn
1.2.4.4 after
发生异常也执行,而afterRetrun发生异常不执行
1.2.5 注意通知执行顺序
aound的before -> before -> 方法执行 -> around 的after-> after-> aftreReturn
发生异常,afterReturn不执行,但是afterReturn执行,around after也没有执行
aound的before -> before -> 方法执行 -> after-> AfterThrowing
1.3 在切面类中实现日志记录
1.3.1 切面类定义
package org.example.Event;
import lombok.extern.slf4j.Slf4j;
import net.minidev.json.JSONObject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect
@Component
@Slf4j
@Order( 0 )
public class SysLogAspect {
@Autowired
private ApplicationContext applicationContext;
private static final ThreadLocal< OptLogDTO> THREAD_LOCAL = new ThreadLocal<> ( ) ;
/***
* 定义controller切入点拦截规则,拦截SysLog注解的方法
*/
@Pointcut( "@annotation(org.example.Event.SysLog)" )
public void mySysLogAspect ( ) {
}
@Before( value = "mySysLogAspect()" )
public void doBefore( JoinPoint joinPoint) {
MethodSignature signature = ( MethodSignature) joinPoint.getSignature( ) ;
Class< ?> aClass = joinPoint.getTarget( ) .getClass( ) ;
Method method = signature.getMethod( ) ;
//log.info( "before" ) ;
System.out.println( "before" + "______" +method.getName( ) + aClass.toString( )) ;
}
@Around( value = "mySysLogAspect()" )
public Object doAround( ProceedingJoinPoint joinPoint) throws Throwable {
Object[ ] args = joinPoint.getArgs( ) ;
for( Object object: args) {
System.out.println( object.toString( )) ;
}
Object proceed = joinPoint.proceed( ) ;
if( proceed instanceof String) {
Object res = ( String) proceed + "加了一点东西" ;
return res;
}
return proceed;
}
// OptLogDTO optLogDTO = THREAD_LOCAL.get( ) ;
// optLogDTO.setDescription( "准备操作" ) ;
// optLogDTO.setRequestIp( "127.0.0.1" ) ;
// optLogDTO.setType( "man" ) ;
// optLogDTO.setUserName( "jack" ) ;
// System.out.println( "around" ) ;
// THREAD_LOCAL.set( optLogDTO) ;
// }
@After( value = "mySysLogAspect()" )
public void doAfter( JoinPoint joinPoint) throws Throwable {
System.out.println( "after" ) ;
}
@AfterReturning( value = "mySysLogAspect()" )
public void doAfterReturn( JoinPoint joinPoint) {
System.out.println( "AfterReturning" ) ;
}
// @Around( value = "mySysLogAspect()" )
// public void doAround( JoinPoint joinPoint) {
// System.out.println( "around" ) ;
// }
@AfterThrowing( value = "mySysLogAspect()" )
public void doAfterThrowing( JoinPoint joinPoint) {
// System.out.println( "success" ) ;
// OptLogDTO optLogDTO = THREAD_LOCAL.get( ) ;
// applicationContext.publishEvent( new SysLogEvent( optLogDTO)) ;
// THREAD_LOCAL.remove( ) ;
System.out.println( "AfterThrowing" ) ;
}
}
1.3.2 在通知中获得事件信息并且发布事件
@Around( value = "mySysLogAspect()" )
public Object doAround( ProceedingJoinPoint joinPoint) throws Throwable {
Object[ ] args = joinPoint.getArgs( ) ;
for( Object object: args) {
System.out.println( object.toString( )) ;
}
Object proceed = joinPoint.proceed( ) ;
//构造操作日志信息
OptLogDTO logInfo = new OptLogDTO( ) ;
logInfo.setRequestIp( "127.0.0.1" ) ;
logInfo.setUserName( "admin" ) ;
logInfo.setType( "OPT" ) ;
logInfo.setDescription( "查询用户信息" ) ;
//构造事件对象
ApplicationEvent event = new SysLogEvent( logInfo) ;
//发布事件
applicationContext.publishEvent( event) ;
if( proceed instanceof String) {
Object res = ( String) proceed + "加了一点东西" ;
return res;
}
return proceed;
}