Spring AOP是面向切面编程,切面有几个重要概念:
切面:连接点、切点、通知所在的【类】就是切面 切点:连接点的集合 连接点:可以理解为spring的方法 通知:切入切点的时机before、after等 业务
在spring-boot中的简单应用
1:在pom中加入aop的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2:编辑切面:
这是一个关于日志的切面(类),
通过@Pointcut("execution(* com.teligen.dazt.learn.spring.aop.service..*.*(..))")设置切点
通过 @Before("logPointCut()") @After("logPointCut()") 设置通知业务。
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
/**
* 一个日志的切面
*/
@Component
@Aspect
public class LogAspect {
private Logger logger = LoggerFactory.getLogger(LogAspect.class);
/**
* 日志切点
*/
@Pointcut("execution(* com.teligen.dazt.learn.spring.aop.service..*.*(..))")
public void logPointCut(){
}
/**
* 日志开始
*/
@Before("logPointCut()")
public void logBefore(){
// logger.info("before ...");
logger.info("before");
}
/**
* 日志结束
*/
@After("logPointCut()")
public void logAfter(){
// logger.info("after ...");
logger.info("after");
}
/**
* 日志环绕
*/
@Around("logPointCut()")
public void logAround(ProceedingJoinPoint joinPoint){
try {
logger.info("around start");
Signature signature = joinPoint.getSignature();
//方法名
String methodName = signature.getName();
//类型
String serviceName = signature.getDeclaringTypeName();
// 参数名数组
String[] parameterNames = ((MethodSignature) signature).getParameterNames();
// 构造参数组集合
List<Object> argList = new ArrayList<>();
for (Object arg : joinPoint.getArgs()) {
// request/response无法使用toJSON
if (arg instanceof HttpServletRequest) {
argList.add("request");
} else if (arg instanceof HttpServletResponse) {
argList.add("response");
} else {
argList.add(JSON.toJSON(arg));
}
}
try {
logger.info("{} -> 方法({}) -> 参数:{} - {}", serviceName, methodName, JSON.toJSON(parameterNames), JSON.toJSON(argList));
} catch (Exception e) {
logger.error("参数获取失败: {}", e.getMessage());
}
long startTime = System.currentTimeMillis();
Object data = joinPoint.proceed();
logger.info("joinPoint.proceed 执行结果: "+data);
long endTime = System.currentTimeMillis();
logger.info("around end 时间:"+(endTime - startTime));
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
}
3:编写相关的测试方法
package com.teligen.dazt.learn.spring.aop.service.impl;
import com.teligen.dazt.learn.spring.aop.service.MyService;
import org.springframework.stereotype.Service;
@Service
public class MyServiceImpl implements MyService {
@Override
public String doAnalyse() throws InterruptedException {
System.out.println("开始进行分析...");
Thread.sleep(1000);
System.out.println("结束分析...");
return "执行成功";
}
}
运行结果:
2020-03-03 15:58:13.046 INFO 15016 --- [nio-8980-exec-1] c.t.dazt.learn.spring.aop.LogAspect : around start
2020-03-03 15:58:13.354 INFO 15016 --- [nio-8980-exec-1] c.t.dazt.learn.spring.aop.LogAspect : com.teligen.dazt.learn.spring.aop.service.impl.MyServiceImpl -> 方法(doAnalyse) -> 参数:[] - []
2020-03-03 15:58:13.397 INFO 15016 --- [nio-8980-exec-1] c.t.dazt.learn.spring.aop.LogAspect : before
开始进行分析...
结束分析...
2020-03-03 15:58:14.406 INFO 15016 --- [nio-8980-exec-1] c.t.dazt.learn.spring.aop.LogAspect : joinPoint.proceed 执行结果: 执行成功
2020-03-03 15:58:14.406 INFO 15016 --- [nio-8980-exec-1] c.t.dazt.learn.spring.aop.LogAspect : around end 时间:1009
2020-03-03 15:58:14.407 INFO 15016 --- [nio-8980-exec-1] c.t.dazt.learn.spring.aop.LogAspect : after