参考文章:简单的aop实现日志打印(切入点表达式)
@Pointcut语法详解
spring 注解aop切入点表达式怎么排除某些方法
目录
1.AOP核心概念
2.JoinPoint 对象
3.简单示例
4.切面文件--use
5.pom.xml文件:
#1、横切关注点
# 对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点
#2、切面(aspect)
# 类是对物体特征的抽象,切面就是对横切关注点的抽象
#3、连接点(joinpoint)
# 被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方
# 法,实际上连接点还可以是字段或者构造器
#4、切入点(pointcut)
# 对连接点进行拦截的定义
#5、通知(advice)
# 所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类
#6、目标对象
# 代理的目标对象
#7、织入(weave)
# 将切面应用到目标对象并导致代理对象创建的过程
#8、引入(introduction)
# 在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段
JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象.
常用api:
方法名 | 功能 |
---|---|
Signature getSignature(); | 获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息 |
Object[] getArgs(); | 获取传入目标方法的参数对象 |
Object getTarget(); | 获取被代理的对象 |
Object getThis(); | 获取代理对象 |
声明一个切面类,并把这个切面类加入到IOC容器中
@Component//加入IOC容器
@Aspect//表示这是一个切面类
public class LogAspect{
// #====================spring 注解aop切入点表达式怎么排除某些方法=================#
// @Pointcut("!execution(* aa.bb..*.set*(..)) && execution(* aa.bb..*.*(..)) ")
// 如果是这种形式的法执行了很多其他方法,比如init。
// @Pointcut("execution(* aa.bb..*.*(..)) && !execution(* aa.bb..*.set*(..)) ")
// 这种形式还是都执行了
//value中为切入点表达式
@Before(value="execution(public void com.bwlu.common.MathCalculatorImpl.*(..))")//前置通知
public void showBeginLog(){
System.out.println("AOP日志开始");
}
@After(value="execution(public void com.bwlu.common.MathCalculatorImpl.*(..))")//后置通知
public void showReturnLog(){
System.out.println("AOP方法结束");
}
@AfterThrowing(value="execution(public void com.bwlu.common.MathCalculatorImpl.*(..))")//异常通知
public void showExceptionLog(){
System.out.println("AOP方法异常");
}
@AfterReturning(value="execution(public void com.bwlu.common.MathCalculatorImpl.*(..))")//返回通知
public void showAfterLog(){
System.out.println("AOP方法最终返回");
}
}
package com.cloud.config;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
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.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
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.io.UnsupportedEncodingException;
import java.net.URLDecoder;
/**
* 实现Web层的日志切面
* 对于同一个代理对象,可以同时有多个切面共同对它进行代理。
* 可以在切面类上通过@Order(value=50)注解来进行设置, 值越小优先级越高
*/
@Component
@Aspect
@Order(1)
public class WebLogAspect {
private Logger log = LoggerFactory.getLogger(getClass());
private ThreadLocal startTime = new ThreadLocal<>();
/**
* 定义一个切入点.
* 解释下:
*
* ~ 第一个 * 代表任意修饰符及任意返回值.
* ~ 第二个 * 任意包名
* ~ 第三个 * 定义在web包或者子包
* ~ 第四个 * 任意方法
* ~ .. 匹配任意数量的参数.
*/
@Pointcut("(execution(public * com.cloud..*Controller.*(..)))")
public void webLog() {
}
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws UnsupportedEncodingException {
startTime.set(System.currentTimeMillis());
// 接收到请求,记录请求内容
log.info("========================= before -- start =========================");
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
log.info("CLASS_METHOD : " + methodSignature.getDeclaringTypeName() + "." + methodSignature.getName());
log.info("请求参数: 名称 值");
String[] argsNameArray = methodSignature.getParameterNames();
Object[] argsValueArray = joinPoint.getArgs();
if (argsNameArray == null || argsNameArray.length < 1) {
log.info("args_name: null");
log.info("args_value: null");
} else {
for (int i = 0; i < argsNameArray.length; i++) {
log.info("args_name: " + argsNameArray[i]);
String argValue = argsValueArray[i] != null ? argsValueArray[i].toString() : "";
if (argsNameArray[i].contains("encode")) {
String str = URLDecoder.decode(argValue, "utf-8");
log.info("args_value: " + (str.length() > 200 ? str.substring(0, 200) + "..." : str));
} else {
log.info("args_value: " + (argValue.length() > 200 ? argValue.substring(0, 200) + "..." : argValue));
}
}
}
// 记录下请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if(attributes == null){
log.info("========================= before -- end =========================");
return;
}
HttpServletRequest request = attributes.getRequest();
log.info("IP : " + request.getRemoteAddr());
log.info("========================= before -- end =========================");
}
@AfterReturning(returning="rvt", pointcut="webLog()")
public void doAfterReturning(JoinPoint joinPoint, Object rvt) {
log.info("========================= after -- start =========================");
log.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName()
+ "." + joinPoint.getSignature().getName());
if(rvt != null){
String str = rvt.toString();
if (str.length() > 200) {
str = str.substring(0, 200) + "...";
}
log.info("return 返回值:");
log.info(str);
}
log.info("耗时(毫秒) : " + (System.currentTimeMillis() - startTime.get()));
log.info("========================= after -- end =========================");
}
}
4.0.0
com.cloud
cloud-base-parent
0.0.1-SNAPSHOT
pom
org.springframework.boot
spring-boot-starter-parent
2.0.5.RELEASE
UTF-8
UTF-8
1.8
Finchley.SR2
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-aop
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
spring-snapshots
Spring Snapshots
https://repo.spring.io/snapshot
true
spring-milestones
Spring Milestones
https://repo.spring.io/milestone
false