package com.example.demo.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class GameDataAspect {
/**
* 定义切入点,切入点为com.example.demo.aop.AopController中的所有函数
*通过@Pointcut注解声明频繁使用的切点表达式
*/
@Pointcut("execution(public * com.example.demo.aop.AopController.Durant(int)) && args(point))")
public void GameDataAspect(int point){
}
/**
* @description 使用环绕通知。point的传参也可以通过反射来解决。
*/
@Around("GameDataAspect(point)")
public void doAroundGameData(ProceedingJoinPoint pjp,int point) throws Throwable {
try{
System.out.println("球星上场前热身!");
pjp.proceed();
System.out.println("球星本场得到" + point + "分" );
}
catch(Throwable e){
System.out.println("异常通知:球迷要求退票!");
}
}
}
一个切面包含多个切点,为每个切点设置通知
1. 切面(aspect)
2. 切点(pointcut)
@Before("execution(* findById*(..)) &&" + "args(id,..)")
public void twiceAsOld1(Long id){
System.err.println ("切面before执行了。。。。id==" + id);
}
参考:Spring AOP execution表达式,拦截 参数被注解注释了的方法
3.@Around(value = "(execution(* com.lxk.service..*(..))) && @annotation(methodLog)", argNames = "joinPoint, methodLog")
public Object methodAround(ProceedingJoinPoint joinPoint, MethodLog methodLog) throws Throwable {
System.out.println("Around method start.......................");
User user = getUserFromSession();
if (user != null) {
System.out.println("Around method " + user.toString());
}
//获得自定义注解的参数
System.out.println("Around method methodLog 的参数,remark:" + methodLog.description() + " clazz:" + methodLog.clazz());
//执行目标方法,并获得对应方法的返回值
Object result = joinPoint.proceed();
System.out.println("Around method 返回结果:" + result);
System.out.println("Around method end.......................");
return result;
}
3. 通知(advice)
try {
//brfore(和around的顺序可调)
{//around开始
//do
}//around结束
//afterreturning(和around的顺序可调)
} catch (Exception e) {
//afterThrowing
} finally {
//after
}
3.1 before
@Before(value = POINT_CUT)
public void before(JoinPoint joinPoint)
3.2 AfterReturning
/**
* 后置返回通知
* 这里需要注意的是:
* 如果参数中的第一个参数为JoinPoint,则第二个参数为返回值的信息
* 如果参数中的第一个参数不为JoinPoint,则第一个参数为returning中对应的参数
* returning:限定了只有目标方法返回值与通知方法相应参数类型时才能执行后置返回通知,否则不执行,
* 对于returning对应的通知方法参数为Object类型将匹配任何目标返回值
* @param joinPoint
* @param keys
*/
@AfterReturning(value = POINT_CUT,returning = "keys")
public void doAfterReturningAdvice1(JoinPoint joinPoint,Object keys){
logger.info("第一个后置返回通知的返回值:"+keys);
}
@AfterReturning(value = POINT_CUT,returning = "keys",argNames = "keys")
public void doAfterReturningAdvice2(String keys){
logger.info("第二个后置返回通知的返回值:"+keys);
}
3.3 AfterThrowing
/**
* 后置异常通知
* 定义一个名字,该名字用于匹配通知实现方法的一个参数名,当目标方法抛出异常返回后,将把目标方法抛出的异常传给通知方法;
* throwing:限定了只有目标方法抛出的异常与通知方法相应参数异常类型时才能执行后置异常通知,否则不执行,
* 对于throwing对应的通知方法参数为Throwable类型将匹配任何异常。
* @param joinPoint
* @param exception
*/
@AfterThrowing(value = POINT_CUT,throwing = "exception")
public void doAfterThrowingAdvice(JoinPoint joinPoint,Throwable exception){
//目标方法名:
logger.info(joinPoint.getSignature().getName());
if(exception instanceof NullPointerException){
logger.info("发生了空指针异常!!!!!");
}
}
3.4 After
/**
* 后置最终通知(目标方法只要执行完了就会执行后置通知方法)
* @param joinPoint
*/
@After(value = POINT_CUT)
public void doAfterAdvice(JoinPoint joinPoint){
logger.info("后置最终通知执行了!!!!");
}
3.5 Around
/**
* 环绕通知:
* 环绕通知非常强大,可以决定目标方法是否执行,什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值。
* 环绕通知第一个参数必须是org.aspectj.lang.ProceedingJoinPoint类型
*/
@Around(value = POINT_CUT)
public Object doAroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
logger.info("环绕通知的目标方法名:"+proceedingJoinPoint.getSignature().getName());
try {
Object obj = proceedingJoinPoint.proceed();
return obj;
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
网友评论