SpringAOP增强-几种不同将注解和切面方法的关联方式
@Around的作用
- 既可以在目标方法之前织入增强动作,也可以在执行目标方法之后织入增强动作;
- 可以决定目标方法在什么时候执行,如何执行,甚至可以完全阻止目标目标方法的执行;
- 可以改变执行目标方法的参数值,也可以改变执行目标方法之后的返回值; 当需要改变目标方法的返回值时,只能使用Around方法;
- 虽然Around功能强大,但通常需要在线程安全的环境下使用。因此,如果使用普通的Before、AfterReturing增强方法就可以解决的事情,就没有必要使用Around增强处理了。
注解方式:如果需要对某一方法进行增强,只需要在相应的方法上添加上自定义注解即可
注解类:
package com.rq.aop.common.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME)//运行时有效 @Target(ElementType.METHOD)//作用于方法 public @interface MyAnnotation { String methodName () default ""; }
将注解和切面方法的关联方式 ---第一种切点方式:
@Around(value = "@annotation(around)") //around 与 下面参数名around对应
public void processAuthority(ProceedingJoinPoint point,MyAnnotation around) throws Throwable{
.....
}
注解上加
@annotation(变量名称),
下面参数加 注解类型+变量名称,
注意,这两个变量名称必须是一样的,这样在加@MyAnnotation 注解方法上,就能切入到此方法上了。
package com.rq.aop.common.advice; import com.rq.aop.common.annotation.MyAnnotation; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Aspect //标注增强处理类(切面类) @Component //交由Spring容器管理 public class AnnotationAspect { /* 可自定义切点位置,针对不同切点,方法上的@Around()可以这样写ex:@Around(value = "methodPointcut() && args(..)") @Pointcut(value = "@annotation(com.rq.aop.common.annotation.MyAnnotation)") public void methodPointcut(){} @Pointcut(value = "@annotation(com.rq.aop.common.annotation.MyAnnotation2)") public void methodPointcut2(){} */ //定义增强,pointcut连接点使用@annotation(xxx)进行定义 @Around(value = "@annotation(around)") //around 与 下面参数名around对应 public void processAuthority(ProceedingJoinPoint point,MyAnnotation around) throws Throwable{ System.out.println("ANNOTATION welcome"); System.out.println("ANNOTATION 调用方法:"+ around.methodName()); System.out.println("ANNOTATION 调用类:" + point.getSignature().getDeclaringTypeName()); System.out.println("ANNOTATION 调用类名" + point.getSignature().getDeclaringType().getSimpleName()); point.proceed(); //调用目标方法 System.out.println("ANNOTATION login success"); } }
将注解和切面方法的关联方式
方式二:直接在切面方法上 指定注解路径
@Before(value = "@annotation(com.cms.common.annotation.ControllerOptLog)") //这里直接 指定注解的位置即可(注解的全路径)。 然后再需要添加注解的方法A上加这个注解,那方法A就能被当前的beforeAdvice()方法所切入。
public void beforeAdvice(JoinPoint joinPoint) throws Throwable { }
@ControllerOptLog public void 方法A(参数类型,变量) throws Exception
{ .....
..... ....... }
方式三:
先将这个注解 和某个方法绑定,然后再在@before注解中指定这个方法: 其实可以理解成是一个间接关联。
注解关联到-方法 方法再关联到曾强的具体逻辑处。
/** * 定义作为切入点的方法 ,并且将切入方法和@ParamValided 关联起来 */ @Pointcut("@annotation(com.atguigu.gulimall.coupon.learn.annotation.ParamValided)") //这里是注解的定义全路径 public void pointcut(){}; @Before(value="pointcut()") public void before(JoinPoint joinPoint) throws Exception{ ................. }
@ParamValided
public void 方法A(参数类型,变量) throws Exception
{ ..........
....... }
方式four: 在上述的两种,不声明切面方法与自定义注解的直接绑定,而是间接的在切面方法中,用到“”是否有这个注解”的判断,如果有这个注解,那再去做一些处理逻辑。这是这种切面方法和自定义注解的关联方式。
自定义注解:MyParamValided
/** * myself自定义的参数校验注解 */ @Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyParamValided { }
切面类中的拦截方法: isValidedAnnotation(mSig.getMethod())
@Slf4j @Aspect @Component public class ParamValidAspect { /** * 依据hibernate.validator校验参数 * * @param joinPoint 连接点 * @return 方法执行结果 * @throws Throwable 调用出错 */ @Around(value = "execution(* com.hbis.cwms.*.controller..*(..))") // @Around(value = "execution(* com.hbis.vesta.controller.**(..))") public Object valid(ProceedingJoinPoint joinPoint) throws Throwable { long beginTime = System.currentTimeMillis(); // 获取业务处理方法注解 MethodSignature mSig = (MethodSignature)joinPoint.getSignature(); Validator v = ApplicationContextRegister.getBean(ValidatorImpl.class); Object[] args = joinPoint.getArgs(); if (args != null && args.length > 0) { for (Object arg : args) { // 判断该方法是否需要校验参数 if (isValidedAnnotation(mSig.getMethod())) { //这里其实就是在判断,当前拦截到的 类的方法的参数上是否有@MyParamValided 这个注解,有的话,则进行下面的校验 ValidatorResult chkRst = beanValidator(v, arg); if (!chkRst.isSucess()) { // 数据校验失败,直接返回错误信息 return Result.error("错误信息提示!") } } } } return joinPoint.proceed(); //切面执行完毕之后,继续执行原始方法 }
判断是否有这个注解的方法具体内容:isValidedAnnotation(Method method) 的具体实现内容
/** * 获取在拦截范围内,所有的方法是否有@MyParamValided 这个注解做注释。 * * @param method 要获取参数名的方法 * @return 按参数顺序排列的参数名列表 */ private boolean isValidedAnnotation(Method method) { Annotation[][] paramAnnotations = method.getParameterAnnotations(); if (paramAnnotations == null || paramAnnotations.length == 0) { return false; } for (Annotation[] parameterAnnotation : paramAnnotations) { for (Annotation annotation : parameterAnnotation) { if (annotation instanceof MyParamValided) { return true; } } } return false; }
校验方法:beanValidator(v, arg); 具体是通过hutool工具做的参数校验,做的是参数实体类的属性上像@Blank @NotBlank等等注解的验证是否符合。
PermissionInterceptor

您的资助是我最大的动力!
金额随意,欢迎来赏!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
2020-03-31 js代码中的parent,top和self有什么区别
2020-03-31 JS window对象的top、parent、opener含义介绍