玩命加载中 . . .

在SpringBoot中用SpringAOP实现日志记录功能


在SpringBoot中用SpringAOP实现日志记录功能

背景:

我需要在一个SpringBoot的项目中的每个controller加入一个日志记录,记录关于请求的一些信息。

代码类似于:

  logger.info(request.getRequestUrl());

之类的。

代码不难,但由于Controller的数量不少,干起来也是体力活。所以想到了用Spring AOP来解决这个问题。

首先,在pom中加入SpringAOP的相关依赖:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

spring中实现aop,需要@Aspect注解,要在spring的配置文件中加入

<aop:aspectj-autoproxy />或者纯注解方式EnableAspectJAutoProxy

那么我们这里要不要在程序的主类中增加@EnableAspectJAutoProxy来启用呢? 实际并不需要,可以看下面关于AOP的默认配置属性,其中spring.aop.auto属性默认是开启的,也就是说只要引入了AOP依赖后,默认已经增加了@EnableAspectJAutoProxy。

好的也就是说,只要引入SpringAOP相关的jar包依赖,我们就可以开始相关的Aspet的编程了。

@Aspect
@Component
public class WebLogAspect {
    
    private final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);
    
    @Pointcut("execution(public * com.stuPayment.controller..*.*(..))")//切入点描述 这个是controller包的切入点
    public void controllerLog(){}//签名,可以理解成这个切入点的一个名称
    
    @Pointcut("execution(public * com.stuPayment.uiController..*.*(..))")//切入点描述,这个是uiController包的切入点
    public void uiControllerLog(){}
    
    @Before("controllerLog() || uiControllerLog()") //在切入点的方法run之前要干的
    public void logBeforeController(JoinPoint joinPoint) {
        
        
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();//这个RequestContextHolder是Springmvc提供来获得请求的东西
        HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
        
         // 记录下请求内容
        logger.info("################URL : " + request.getRequestURL().toString());
        logger.info("################HTTP_METHOD : " + request.getMethod());//请求方式get/post
        logger.info("################IP : " + request.getRemoteAddr());
        logger.info("################THE ARGS OF THE CONTROLLER : " + Arrays.toString(joinPoint.getArgs()));
        
        //下面这个getSignature().getDeclaringTypeName()是获取包+类名的   然后后面的joinPoint.getSignature.getName()获取了方法名
        logger.info("################CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());

    }
  
}

注解

@Aspect和@Component

首先,这个@Aspect注释告诉Spring这是个切面类,然后@Compoment将转换成Spring容器中的bean或者是代理bean。 总之要写切面这两个注解一起用就是了。

既然是切面类,那么肯定是包含PointCut还有Advice两个要素的,下面对几个注解展开讲来看看在@Aspect中是怎么确定切入点(PointCut)和增强通知(Advice)的。

@PointCut(表达式)

切入点,包含表达式、签名两部分,

表达式是拿来确定切入点的位置的,说白了就是通过一些规则来确定,哪些方法是要增强的,也就是要拦截哪些方法。

签名就是方法名,没有实际用处,就是唯一标识

@Before(签名/表达式)

标注在通知方法上,标识在方法前执行……

然后看到注解下面的方法,就是描述advice的,我们看到有个参数JoinPoint,这个东西代表着织入增强处理的连接点。JoinPoint包含了几个很有用的参数:

  • Object[] getArgs:返回目标方法的参数
  • Signature getSignature:返回目标方法的签名
  • Object getTarget:返回被织入增强处理的目标对象
  • Object getThis:返回AOP框架为目标对象生成的代理对象

除了注解@Around的方法外,其他都可以加这个JoinPoint作参数。@Around注解的方法的参数一定要是ProceedingJoinPoint,下面会介绍。

@Around

环绕通知,参数一定要是ProceedingJoinPoint,我们可以把它看作被增强方法的替身,这个proceedingJoinPoint有个proceed()方法,相当于就是那切入点的那个方法执行,简单地说就是让目标方法执行,然后这个方法会返回一个对象,这个对象就是那个切入点所在位置的方法所返回的对象。

@AfterReturning

执行后通知,这个注解可以指定两个属性,第一个是pointcut切入点表达式/签名,第二个是returning属性,表明可以在Advice的方法中有目标方法返回值的形参。

@AfterThrowing

异常抛出增强,在异常抛出后织入的增强。有点像上面的@AfterReturning,这个注解也是有两个属性,pointcut和throwing。


RequestContextHolder

这里还要提到上面用到的一个类,java类中想要获得request和response对象,可以使用springmvc提供的这个类。

RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
//从session里面获取对应的值
String str = (String) requestAttributes.getAttribute("name",RequestAttributes.SCOPE_SESSION);
 
HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
HttpServletResponse response = ((ServletRequestAttributes)requestAttributes).getResponse();

request能获得什么信息

请求URL:request.getRequestURL().toString())

请求方式(get/post):request.getMethod()

请求IP:request.getRemoteAddr()

joinPoint能获得什么信息

包名:joinPoint.getSignature().getDeclaringTypeName()

方法名:joinPoint.getSignature().getName()

方法参数:joinPoint.getArgs()


文章作者: 小苏
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 小苏 !
评论
  目录