前言
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