Aspect
前言
Github:https://github.com/HealerJean
一、全部类切面
1、自定义 Pointcut
默认情况下,匹配所有的类,这里配置是否需要拦截
public class CustomStatusPointcut extends StaticMethodMatcherPointcutAdvisor {
/**
* 切点方法 匹配
* 匹配规则: 默认情况下,匹配所有的类
*/
@Override
public boolean matches(Method method, Class<?> clazz) {
return Optional.ofNullable(clazz.getName()).map(item -> item.contains("Controller")).orElse(false);
}
}
2、自定义 Advice
对
Pointcut拦截的方式进行切面处理,这个advice就是我们需要执行的切面逻辑
@Slf4j
public class CustomStatusAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation joinPoint) throws Throwable {
Method method = joinPoint.getMethod();
String className = null;
String methodName = null;
Object[] args = joinPoint.getArguments();
long start = System.currentTimeMillis();
Object result = null;
Object reqParams = null;
try {
methodName = method.getName();
className = method.getDeclaringClass().getName();
Parameter[] parameters = method.getParameters();
reqParams = getRequestParams(args, parameters);
result = joinPoint.proceed();
} finally {
long timeCost = System.currentTimeMillis() - start;
Map<String, Object> map = new HashMap<>(8);
map.put("method", className + "." + methodName);
map.put("requestParams", reqParams);
map.put("responseParams", result);
map.put("timeCost", timeCost + "ms");
log.info("LogAspect:{}", JsonUtils.toJsonString(map));
}
return result;
}
/**
* 重构请求参数
*
* @param args 参数
* @param parameters 参数名
* @return 重构后的请求参数
*/
public Object getRequestParams(Object[] args, Parameter[] parameters) {
if (Objects.isNull(args)) {
return null;
}
if (args.length == 1 && !(args[0] instanceof HttpServletRequest) && !(args[0] instanceof HttpServletResponse)) {
return args[0];
}
List<Object> result = new ArrayList<>();
try {
for (int i = 0; i < args.length; i++) {
Object param = args[i];
if (param instanceof HttpServletRequest) {
result.add("HttpServletRequest");
continue;
}
if (param instanceof HttpServletResponse) {
result.add("HttpServletResponse");
continue;
}
Map<Object, Object> map = new HashMap<>(2);
map.put(parameters[i].getName(), param);
result.add(map);
}
} catch (Exception e) {
log.warn("LogAspect getRequestParams error:{}", ExceptionUtils.getStackTrace(e));
}
return result;
}
}
3、自定义 Advisor
将上面自定义的切点
pointcut与通知advice整合,实现我们的切面
@Setter
public class CustomStatusAdvisor extends AbstractBeanFactoryPointcutAdvisor {
private Pointcut customStatusPointcut;
@Override
public Pointcut getPointcut() {
return customStatusPointcut;
}
}
4、Bean 注入
@Configuration
public class CustomStatisPointConfig {
@Bean
public CustomStatusAdvisor init() {
CustomStatusAdvisor customStatusAdvisor = new CustomStatusAdvisor();
customStatusAdvisor.setCustomStatusPointcut(new CustomStatusPointcut());
customStatusAdvisor.setAdvice(new CustomStatusAdvice());
return customStatusAdvisor;
}
}
二、Aspect
1、pom依赖
<!-- aop 切面 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2、Service
1)接口 DemoEntityService
package com.healerjean.proj.service;
import com.healerjean.proj.dto.Demo.DemoDTO;
public interface DemoEntityService {
DemoDTO getMmethod(DemoDTO demoEntity);
}
2)DemoEntityServiceImpl
@Service
@Slf4j
public class DemoEntityServiceImpl implements DemoEntityService {
@Override
public DemoDTO getMmethod(DemoDTO demoEntity) {
log.info("Service--------getMmethod");
// int i = 1/0;
return demoEntity;
}
}
3)Aspect
package com.healerjean.proj.config.aspect;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Aspect //当前类标识为一个切面供容器读取 ,、@Aspect放在类头上,把这个类作为一个切面。
@Order(2) // 控制多个Aspect的执行顺序,越小越先执行
@Slf4j
public class AspectStyleMethod {
/**
* @Pointcut 放在方法头上,定义一个可被别的方法引用的切入点表达式
*/
@Pointcut("execution(* com.healerjean.proj.service.*Service.*(..))")
private void anyMethod() {
}
/**
* @Before 标识一个前置增强方法
*/
@Before("anyMethod()")
public void before() {
log.info("@Before");
}
/**
* @After: final增强,不管是抛出异常或者正常退出都会执行
*/
@After("anyMethod()")
public void after() {
log.info("@After");
}
/**
* @AfterReturning :后置增强,方法正常退出时执行(有了异常就不会执行)
*/
@AfterReturning("anyMethod()")
public void afterReturning() {
log.info("@AfterReturning");
}
/**
* @AfterThrowing: 异常抛出增强,(有了异常才会执行,否则不能够执行(在around异常处理之前执行))
*/
@AfterThrowing("anyMethod()")
public void afterThrowing() {
log.info(" @AfterThrowing");
}
/**
* 正常调用
* @Around: 环绕增强
*/
@Around("anyMethod()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
log.info("@Around pjp.proceed() 准备执行");
Object object = pjp.proceed();
//下面的log.info不会执行,因为AspectStyleService中有了异常,所以不会到这一步
log.info("@Around pjp.proceed() 执行完毕");
return object;
}
}
3、注解解释
1)@Before、@After
@Before,@After是在方法pjp.proceed()执行的前后
@Around pjp.proceed() 准备执行 com
@Before
Service--------getMmethod com.
@Around pjp.proceed() 执行完毕
@After
@AfterReturning
2)异常不捕获
@Around pjp.proceed() 准备执行
@Before
Service--------getMmethod
@After
@AfterThrowing
3)异常捕获
@Around先捕获异常,然后才执行@After,@AfterThrowing
/**
* 异常捕获
* @Around: 环绕增强
*/
@Around("anyMethod()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
log.info("@Around pjp.proceed() 准备执行");
try {
Object object = pjp.proceed();
//下面的log.info不会执行,因为AspectStyleService中有了异常,所以不会到这一步
log.info("@Around pjp.proceed() 正常执行完毕");
return object;
} catch (Exception e) {
log.info("@Around pjp.proceed() 出错:{}", e.getMessage());
throw e;
}
}
@Around pjp.proceed() 准备执行
@Before
Service--------getMmethod
@Around pjp.proceed() 出错:/ by zero
@After
@AfterThrowing
4)@Pointcut
* 匹配任意字符,但只能匹配一个元素
.. 匹配任意字符,可以匹配任意多个元素,表示类时,必须和*联合使用
+ 必须跟在类名后面,如Horseman+,表示类本身和继承或扩展指定类的所有类
1、类切面
@Pointcut("execution(* com.healerjean.proj.controller.*Controller.*(..))")
2、包切面
@Pointcut("execution(* com.jdd.baoxian.core.trade.merchant..*(..))")
1、execution(public * * (. .)) 任意公共方法被执行时,执行切入点函数。
2、execution( * set* (. .)) 任何以一个“set”开始的方法被执行时,执行切入点函数。
3、execution( * com.demo.service.AccountService.*(..)) 当接口AccountService 中的任意方法被执行时,执行切入点函数。
4、execution( * com.demo.service..*(..)) 当service 包中的任意方法被执行时,执行切入点函数。
多个切点
@Around("execution(* com.fintech.manager.controller.*.*Controller.*(..))" +
"|| execution(* com.fintech.manager.task.*Task.*(..))")


