springboot自定义注解不生效情况分析及解决方案

前言

一、Spring AOP的实现机制

 

二、EnableAspectJAutoProxy的使用

1.使用XML的配置:

2.使用注解配置

总结


前言

SpringBoot中自定义注解不生效情况分析及解决方案。

背景:因项目需要,通过自定义注解实现了一个令牌桶功能。在测试的时候,自定义注解加在Controller层的带RequestMapping注解的方法上,Service层中实现自接口的方法上,都能生效。一旦把注解加在普通方法上,注解就失效了。网上找了很多资料,有一种说法是包扫描的问题。我遇到的情况不是包扫描不到的问题。无意中看到一个讲Spring Aop实现机制的文章,提到了动态代理,参照文章修改项目,解决了问题。下面详细记录一下问题及处理问题的方法

 

一、Spring AOP的实现机制

基于spring aop实现的注解,在spring中,如果有aop实现,那么容器注入的是该类的代理类。spring aop的动态代理有两种:一种是jdk的动态代理,一种是基于CGLIB的,这两个的区别自己查资料。在这里我知道了aop是基于动态代理实现的。看下面的代码:

@Service
public class RateLimitServiceImpl implements RateLimitService {
    @Autowired
    RedisTemplate<String, Serializable> redisTemplate;

    @Override
    public String testRateLimit() {
        return test();
    }

    @RateLimit(key = "test", time = 10, count = 5)
    public String test(){
        RedisAtomicInteger entityIdCounter = new RedisAtomicInteger("entityIdCounter", redisTemplate.getConnectionFactory());
        String date = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");

        return date + "累计访问次数:" + entityIdCounter.getAndIncrement();
    }
}

上一级方法在调用testRateLimit方法的时候,是通过的spring托管的类的代理请求的。如果@RateLimit注解放在testRateLimit方法上,那么注解是可以生效的。但是注解如果如示例代码中那样放在普通的类方法test上,那么注解是不会生效的。这是因为,test方法的调用是在testRateLimit方法内部调用的,所以在这里实际调用test的是真实对象,不是代理对象。所以test方法上的限流注解没有生效。也就是说内部调用不走代理类,所以附加的注解也就不会执行了。那么我们的解决思路就出来了,怎么样让test被代理类调用。

 

二、EnableAspectJAutoProxy的使用

@EnableAspectJAutoProxy - 开启对AspectJ自动代理技术

1.使用XML的配置:

<aop:aspectj-autoproxy expose-proxy="true" proxy-target-class="true" />

2.使用注解配置

我是springboot项目,使用的注解来配置

@Service
@EnableAspectJAutoProxy(exposeProxy = true)
public class RateLimitServiceImpl implements RateLimitService {
    @Autowired
    RedisTemplate<String, Serializable> redisTemplate;

    @Override
    public String testRateLimit() {
        return ((RateLimitServiceImpl)AopContext.currentProxy()).test();
    }

    @RateLimit(key = "test", time = 10, count = 5)
    public String test(){
        RedisAtomicInteger entityIdCounter = new RedisAtomicInteger("entityIdCounter", redisTemplate.getConnectionFactory());
        String date = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");

        return date + "累计访问次数:" + entityIdCounter.getAndIncrement();
    }
}

这段代码跟上一段代码的区别就是RateLimitServiceImpl类上多了一个EnableAspectJAutoProxy注解,

testRateLimit方法的实现,调用test方法的方式变成了通过AopContext.CurrentProxy来代理

这样,问题就解决了。


总结

以上就是对于特殊业务场景注解的使用方法说明,并不仅限于自定义注解,官方注解也同样适用。感谢两篇文章的支持。

参考:https://segmentfault.com/a/1190000014346303?utm_source=tag-newest

https://blog.csdn.net/rtuujnncc/article/details/68926465?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.edu_weight&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.edu_weight


版权声明:本文为badkid123原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。