同一个类中调用方法spring AOP未被触发

前几天部门有个活,需要对一些敏感信息字段进行脱敏,正好团队内部几个系统都有这个需求,
我一想,这不是个很好的应用AOP的场景吗?
正好刚重新温习了遍AOP,应用到实际场景的机会就来了。
撸起袖子,说干就干。
由于需求明确,实现起来很顺利,跑完UT后,结果一片飘绿,非常开心的推荐给相关的几个系统使用,我还得意得沉浸在学以致用的喜悦中没多久,A同学跑过来说,你这个AOP应用不到啊!
简直是当头一棒!
先讲一下我的实现方案:
  • 1. 定义脱敏字段注解,对需要脱敏字段选择合适脱敏方法
  • @Target(value = {ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface MaskFields{
    }
    
  • 2. 定义脱敏方法注协,告诉AOP切面,哪些方法是需要脱敏处理的
  • @Target(value = {ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface MaskMethod{
    }
    

  • 3. 实现脱敏切面
  • @Component
    @Aspect
    public class MaskAop {
        private Logger logger = LoggerFactory.getLogger(getClass());
    
        @Pointcut("@annotation(MaskMethod)")
        public void pointcut() {
        }
    
        // 定义 advise
        @Before("pointcut()")
        public void maskFieldProcess(JoinPoint joinPoint) {
            logger.info("---Before method {} invoke, param: {}---", joinPoint.getSignature().toShortString(), joinPoint.getArgs());
        }
    }


  • 4. 在spring的配置文件中,打开AOP的代理
  • <aop:aspectj-autoproxy/>  
    <aop:aspectj-autoproxy proxy-target-class="true"/>  



    然后我仔细检查了A同学的使用方式,

    @Service
    public class SomeService {
        private Logger logger = LoggerFactory.getLogger(getClass());
    
        public List<UserVo> getUserList(String someParam) {
            List<UserModel> userModelList= userDao.getUsers();
            return modelToVo(userModelList)
        }
    
        @MaskMethod
        public void modelToVo() {
    
        }
    }


    经过debug调试,发现这个方法根本没有被AOP拦截到!查阅资料,发现这算是spring AOP的一个限制. spring AOP 并不是扩展了一个类(目标对象), 而是使用了一个代理对象来包装目标对象, 并拦截目标对象的方法调用. 这样的实现带来的影响是: 在目标对象中调用自己类内部实现的方法时, 这些调用并不会转发到代理对象中, 甚至代理对象都不知道有此调用的存在!

    知道问题的原因,解决方法就简单了,给自己定义个内部的引用,通过这个引用去调方法就能被AOP拦截到了。

    @Service
    public class SomeService {
        private Logger logger = LoggerFactory.getLogger(getClass());
    
        private SomeService self;
    
        public List<UserVo> getUserList(String someParam) {
            List<UserModel> userModelList= userDao.getUsers();
            return self.modelToVo(userModelList)
        }
    
        @MaskMethod
        public void modelToVo() {
    
        }
    }


    当然,更合理的是提取一个转换的servuce类,把这种转换方法提取到这个类里面,统一进行拦截。

    猜你喜欢

    转载自zenghuiss.iteye.com/blog/2407749