参考:iteye_16572 – https://blog.csdn.net/iteye_16572/article/details/82677981 参考:山高我为峰 – https://www.cnblogs.com/liaojie970/p/7883687.html
实现AOP的切面主要有以下几个要素:
- 使用@Aspect注解将一个java类定义为切面类
- 使用
@Pointcut
定义一个切入点,可以是一个规则表达式,比如下例中某个package下的所有函数,也可以是一个注解等。- 修饰符匹配(modifier-pattern?)
- 返回值匹配(ret-type-pattern)可以为*表示任何返回值,全路径的类名等
- 类路径匹配(declaring-type-pattern?)
- 方法名匹配(name-pattern)可以指定方法名 或者 代表所有, set 代表以set开头的所有方法
- 参数匹配((param-pattern))可以指定具体的参数类型,多个参数间用“,”隔开,各个参数也可以用“”来表示匹配任意类型的参数,如(String)表示匹配一个String参数的方法;(,String) 表示匹配有两个参数的方法,第一个参数可以是任意类型,而第二个参数是String类型;可以用(..)表示零个或多个任意参数
- 异常类型匹配(throws-pattern?)
- 其中后面跟着“?”的是可选项
// 栗子: 1)execution(* *(..)) //表示匹配所有方法 2)execution(public * com. savage.service.UserService.*(..)) //表示匹配com.savage.server.UserService中所有的公有方法 3)execution(* com.savage.server..*.*(..)) //表示匹配com.savage.server包及其子包下的所有方法
- 根据需要在切入点不同位置的切入内容
- 使用@Before在切入点开始处切入内容
- 使用@After在切入点结尾处切入内容
- 使用@AfterReturning在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理)
- 使用@Around在切入点前后切入内容,并自己控制何时执行切入点自身的内容
- 使用@AfterThrowing用来处理当切入内容部分抛出异常之后的处理逻辑
栗子:
import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
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;
// ① 在类上使用 @Component 注解 把切面类加入到IOC容器中
// ② 在类上使用 @Aspect 注解 使之成为切面类
@Aspect
@Component
public class ControllerLogAspect {
private Logger logger = LoggerFactory.getLogger(ControllerLogAspect.class);
private ThreadLocal<Long> startTime = new ThreadLocal<Long>();
@Pointcut("execution(public * .*.controller..*.*(..))")
public void controllerLog() {}
@Before("controllerLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
ServletRequestAttributes attributes =
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 请求内容
logger.info("请求地址 : " + request.getRequestURL().toString()
+ ",参数 : " + Arrays.toString(joinPoint.getArgs())
+ ",请求方法 : " + request.getMethod()
+ ",IP: " + request.getRemoteAddr()
+ ",CLASS_METHOD: " + joinPoint.getSignature().getDeclaringTypeName() + "."
+ joinPoint.getSignature().getName());
}
@AfterReturning(returning = "ret", pointcut = "controllerLog()")
public void doAfterReturning(Object ret) throws Throwable {
// 返回内容
logger.info("返回值 : " + ret);
}
@Around("controllerLog()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
startTime.set(System.currentTimeMillis());
Object ob = pjp.proceed();// ob 为方法的返回值
logger.info("耗时 : " + (System.currentTimeMillis() - startTime.get()));
return ob;
}
}
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
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;
// ① 在类上使用 @Component 注解 把切面类加入到IOC容器中
// ② 在类上使用 @Aspect 注解 使之成为切面类
@Aspect
@Component
public class ServiceLogAspect {
private Logger logger = LoggerFactory.getLogger(ServiceLogAspect.class);
private ThreadLocal<Long> startTime = new ThreadLocal<Long>();
@Pointcut("execution(public * .*.service..*.*(..))")
public void serviceLog() {}
@Before("serviceLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
// 请求内容
logger.info("CLASS_METHOD: " + joinPoint.getSignature().getDeclaringTypeName() + "."
+ joinPoint.getSignature().getName() + ",参数 : "
+ Arrays.toString(joinPoint.getArgs()));
}
@AfterReturning(returning = "ret", pointcut = "serviceLog()")
public void doAfterReturning(Object ret) throws Throwable {
// 返回内容
logger.info("返回值 : " + ret);
}
@Around("serviceLog()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
startTime.set(System.currentTimeMillis());
Object ob = pjp.proceed();// ob 为方法的返回值
logger.info("耗时 : " + (System.currentTimeMillis() - startTime.get()));
return ob;
}
}
文章中若有不足之处,还望指出。坚持是一种精神,分享是一种快乐!