剑客
关注科技互联网

切面编程(二):基于注解的切面类使用

定义一个切面类

可以使用注解@Aspect定义一个切面类,最常用的就是日志追踪

@Aspect     //定义该类为切面
@Component //让Spring扫描加入控制反转
@Slf4j //Lombok的日志打印
public class ServiceLogAspect {
......
}

寻找切点(PointCut)

动态代理理解的透彻的话,我们可以发现,其是针对某个接口下 一组方法
进行的控制,如果想具体到 某一个方法
需要自己在 invoke函数的参数method
进行逻辑判断,而切点则不用,其通过表达式(就是规定好的字符串)方法可以控制到 一个方法or一个接口or一个包下所有类 不同的具体程度

@Pointcut(value = "execution(public * com.company.service.impl..*.*(..))")
public void logService() {

}

@Before(value = "logService()")
public void logBefore(JoinPoint joinPoint) {

}

@After(value = "logService()")
public void logAfterReturning(JoinPoint joinPoint) {

}

表达式
execution(public com.company.service.impl..
.*(..))

的意思是

  1. execution(…) 执行某个函数
  2. 某个函数是public类型的
  3. 返回值是 * 代表任意类型
  4. impl后的两个点 .. 代表在包名com.company.service.impl目录和其子目录下
  5. ..*. 代表目录和其子目录下任意一个Class(如果是 ..*user. 的意思就是结尾为user的Class)
  6. 最后括号前的 *(..) 代表任意方法和任意参数,括号内是参数

后边的Before和After就很好理解啦,就是以下方法在动态代理的方法前还是之后执行,除了Before和After还有Around和AfterThrowing、AfterReturning

除了使用以上的编程习惯,也可以直接在其余注解中使用表达式,例如@Before(value = “execution(public com.company.service.impl..
.*(..))”)

Spring Aspect表达式的官方文档节选

* execution - for matching method execution join points, this is the primary pointcut designator you will use when working with Spring AOP
* within - limits matching to join points within certain types (simply the execution of a method declared within a matching type when using Spring AOP)
* this - limits matching to join points (the execution of methods when using Spring AOP) where the bean reference (Spring AOP proxy) is an instance of the given type
* target - limits matching to join points (the execution of methods when using Spring AOP) where the target object (application object being proxied) is an instance of the given type
* args - limits matching to join points (the execution of methods when using Spring AOP) where the arguments are instances of the given types
* @target - limits matching to join points (the execution of methods when using Spring AOP) where the class of the executing object has an annotation of the given type
* @args - limits matching to join points (the execution of methods when using Spring AOP) where the runtime type of the actual arguments passed have annotations of the given type(s)
* @within - limits matching to join points within types that have the given annotation (the execution of methods declared in types with the given annotation when using Spring AOP)
* @annotation - limits matching to join points where the subject of the join point (method being executed in Spring AOP) has the given annotation

JointPoint是什么

JointPoint是一个包裹了在动态代理中,调用了哪个方法,哪个类,以及都有什么参数的Object,例如

/**
* 获取连接点的方法
*/

static public Method getInvokeMethod(JoinPoint joinPoint) {
MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
return methodSignature.getMethod();
}

/**
* 获得连接点的Field
*/

static public Field[] getFields(JoinPoint joinPoint) {
Field[] fields = joinPoint.getTarget().getClass().getDeclaredFields();
return fieldList;
}

/**
* 获得连接点的参数
*/

static public Object[] getParamters(JoinPoint joinPoint) {
return joinPoint.getArgs();
}

获得切面方法抛出的异常和返回值

除了可以或者我们切面的方法和参数信息,还可以获得到万一抛出了异常或者执行完毕后的值

/**
* 定义抛出类的型参名称为ex,并传入切面
*/

@AfterThrowing(value = "logService()", throwing = "ex")
public void logAfterThrowing(JoinPoint joinPoint, Exception ex) {
String message = (ex.getMessage() == null)?ex.getClass().getName():ex.getMessage();
log.warn("方法抛出异常: {} ",message);
}

/**
* 定义返回值的型参名称为r,并传入切面
*/

@AfterReturning(value = "logService()", returning = "r")
public void logAfterReturning(JoinPoint joinPoint, Object r) {
log.info("方法调用结束 返回值:{}",r.toString());
}

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址