说起spring,我们知道其最核心的两个功能就是AOP(面向切面)和IOC(控制反转),这边文章来总结一下SpringBoot如何整合使用AOP。
一、示例应用场景:对所有的web请求做切面来记录日志。
1、pom中引入SpringBoot的web模块和使用AOP相关的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入AOP依赖start-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.11</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.11</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1</version>
</dependency>
其中:
cglib包是用来动态代理用的,基于类的代理;
aspectjrt和aspectjweaver是与aspectj相关的包,用来支持切面编程的;
aspectjrt包是aspectj的runtime包;
aspectjweaver是aspectj的织入包;
写个controller,路径在:
com.hy.bb.web.controller下面
3、定义切面类,实现web层的日志切面
要想把一个类变成切面类,需要两步,
① 在类上使用 @Component 注解 把切面类加入到IOC容器中
② 在类上使用 @Aspect 注解 使之成为切面类
package com.hy.bb.web.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
@Aspect
@Component
public class WebLogAcpect {
private Logger logger = LoggerFactory.getLogger(WebLogAcpect.class);
/**
* 定义切入点,切入点为com.hy.bb.web.controller下的所有函数
*/
@Pointcut("execution(public * com.hy.bb.web.controller..*.*(..))")
public void webLog(){}
/**
* 前置通知:在连接点之前执行的通知
* @param joinPoint
* @throws Throwable
*/
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
System.out.println("============----------=========");
// 记录下请求内容
logger.info("URL : " + request.getRequestURL().toString());
logger.info("HTTP_METHOD : " + request.getMethod());
logger.info("IP : " + request.getRemoteAddr());
logger.info("CLASS_METHOD : " +
joinPoint.getSignature().getDeclaringTypeName() + "." +
joinPoint.getSignature().getName());
logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
// 通知的签名
Signature signature = joinPoint.getSignature();
//AOP代理的类名和方法名
logger.info("类名 :"+signature.getDeclaringTypeName()+" "+" 方法名:"+signature.getName());
System.out.println("============----------=========");
}
@AfterReturning(returning = "ret",pointcut = "webLog()")
public void doAfterReturning(Object ret) throws Throwable {
// 处理完请求,返回内容
logger.info("RESPONSE : " + ret);
}
}
execution详解: https://blog.csdn.net/kkdelta/article/details/7441829
以上的切面类通过 @Pointcut定义的切入点为com.hy.bb.web.controller 包下的所有函数做切人,通过 @Before实现切入点的前置通知,通过 @AfterReturning记录请求返回的对象。
测试: