阅读 297

SpringAop @Aspect织入不生效,不执行前置增强织入@Before方式

这篇文章主要介绍了SpringAop @Aspect织入不生效,不执行前置增强织入@Before方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

目录
  • SpringAop @Aspect织入不生效,不执行前置增强织入@Before

    • 想写一个AOP,主要有2个用意

  • 使用@Aspect,@Before不被调用

    SpringAop @Aspect织入不生效,不执行前置增强织入@Before

    想写一个AOP,主要有2个用意

    • 第一个用意是做后端的防表单重复提交的token验证。

    • 第二个用意是对后台JSR303 Validator的校验结果做一个统一处理,不想把对校验结果的处理分散在每个controller方法中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @ResponseBody
        @RequestMapping(value = "add", method = RequestMethod.POST)
        public ResponseModel add(@Valid User user, BindingResult br, HttpServletResponse response) {
             
            if(br.hasErrors()) {
                return ResponseModel.validFail(getErrorsSplitNewLine(br));
            }
            accountService.addUser(user);
            return ResponseModel.success("保存用户成功");
        }

    如上面方法中, br.hasErrors() 在每个表单提交方法中都存在,想单独抽出来使用AOP统一处理。

    所以写一个AOP,如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Aspect
    @Component
    public class ParamValidAspect {
        @Before("@annotation(com.hebao.tech.adm.framework.annotation.ParamValid)")
        public void paramValid(JoinPoint point) {
        System.out.println("参数校验切入方法被调用了.....");
            //省略
        }
    }

    由于这篇文章主要是记录AOP不生效的原因,所以,这里不写具体实现了。

    上面的内容定义一个Aop织入,在有注解@ParamValid的注释Controller方法上织入。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
      
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ParamValid {
      
    }

    这个ParamValid的内容,仅仅是一个标志性的注解,声明为方法层的注解,并且是运行时注解。

    最后在application.xml中加入AOP动态代理设置。

    1
    2
    <!-- 这个配置要配置在component-scan以后 -->
    <aop:aspectj-autoproxy proxy-target-class="true" />

    如果spring配置文件没引入过aop的配置,还需要在加入xml声明


    大功告成,测试了一下,发现有点悲剧,根本织入不生效,也不报错,,楞是不执行相关的织入代码。

    最后在网上搜了一下,发现Spring与SpringMVC是2个不同的父子容器, @Aspect如果被spring容器加载的话,而@Controller注解的这些类的实例化以及注入却是由SpringMVC来完成。 @Aspect如果被spring容器加载的时候,可能Spring MVC容器还未初始化, Controller类还未初始化,所以无法正常织入。。

    所以调整如下:

    1
    2
    3
    4
    5
    6
    7
    8
    @Aspect
    public class ParamValidAspect {
        @Before("@annotation(com.hebao.tech.adm.framework.annotation.ParamValid)")
        public void paramValid(JoinPoint point) {
     System.out.println("参数校验切入方法被调用了.....");
            //省略
        }
    }

    去掉@Component注解,然后把 aop:aspectj-autoproxy 移入springmvc配置文件中,并定义bean,如下:

    1
    2
    3
    <!-- 这个配置一定要配置在component-scan以后 -->
    <aop:aspectj-autoproxy proxy-target-class="true" />
    <bean id="paramValidAspect" class="com.hebao.tech.adm.framework.spring.aop.ParamValidAspect"/>

    这样就大功告成了。

    使用@Aspect,@Before不被调用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    @Aspect
    @Component
    public class LogAspect {
        @Before("pointcut()")
        public void before(){
            System.out.println("before");
        }
      
        @Pointcut("@annotation(com.demo.annotation.Log)")
        public void pointcut(){    
        }
      
        @Around("pointcut()")
        public void around(){
            System.out.println("arount");
        }
      
        @After("pointcut()")
        public void after(){
            System.out.println("after");
        }
    }

    调用方法返回结果:

    arount

    after

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    @Aspect
    @Component
    public class LogAspect {
        @Before("pointcut()")
        public void before(){
            System.out.println("before");
        }
      
        @Pointcut("@annotation(com.mxy.annotation.Log)")
        public void pointcut(){
             
        }
      
        @Around("pointcut()")
        public void around(ProceedingJoinPoint point){
            System.out.println("arount before");
      
            try {
                point.proceed();
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            System.out.println("arount after");
        }
      
        @After("pointcut()")
        public void after(){
            System.out.println("after");
        }
    }

    调用返回结果:

    arount before

    before

    arount after

    after

    以上为个人经验,希望能给大家一个参考

    原文链接:https://blog.csdn.net/oKuZuoZhou/article/details/81015310


      文章分类
      百科问答
      版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
      相关推荐