一个Spring AOP的坑!很多人都犯过!
问题重现
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Cacheable {
/**
* 策略名称,需要保证唯一
* @return
*/
public String keyName();
/**
* 超时时长,单位:秒
* @return
*/
public int expireTime();
}
@Aspect
@Component
public class StrategyCacheAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(FacadeAspect.class);
@Around("@annotation(com.hollis.cache.StrategyCache)")
public Object cache(ProceedingJoinPoint pjp) throws Throwable {
// 先查缓存,如果缓存中有值,直接返回。如果缓存中没有,先执行方法,再将返回值存储到缓存中。
}
}
@Component
public class StrategyService extends BaseStrategyService {
public PricingResponse getFactor(Map<String, String> pricingParams) {
// 做一些参数校验,以及异常捕获相关的事情
return this.loadFactor(tieredPricingParams);
}
@Override
@StrategyCache(keyName = "key0001", expireTime = 60 * 60 * 2)
private PricingResponse loadFactor(Map<String, String> pricingParams) {
//代码执行
}
}
问题排查
代理的调用方式
public class SimplePojo implements Pojo {
public void foo() {
// this next method invocation is a direct call on the 'this' reference
this.bar();
}
public void bar() {
// some logic...
}
}
public class Main {
public static void main(String[] args) {
Pojo pojo = new SimplePojo();
// this is a direct method call on the 'pojo' reference
pojo.foo();
}
}
public class Main {
public static void main(String[] args) {
ProxyFactory factory = new ProxyFactory(new SimplePojo());
factory.addInterface(Pojo.class);
factory.addAdvice(new RetryAdvice());
Pojo pojo = (Pojo) factory.getProxy();
// this is a method call on the proxy!
pojo.foo();
}
}
问题解决
获取代理对象进行调用
@Component
public class StrategyService{
public PricingResponse getFactor(Map<String, String> pricingParams) {
// 做一些参数校验,以及异常捕获相关的事情
// 这里不使用this.loadFactor而是使用AopContext.currentProxy()调用,目的是解决AOP代理不支持方法自调用的问题
if (AopContext.currentProxy() instanceof StrategyService) {
return ((StrategyService)AopContext.currentProxy()).loadFactor(tieredPricingParams);
} else {
// 部分实现没有被代理过,则直接进行自调用即可
return loadFactor(tieredPricingParams);
}
}
@Override
@StrategyCache(keyName = "key0001", expireTime = 60 * 60 * 2)
private PricingResponse loadFactor(Map<String, String> oricingParams) {
//代码执行
}
}
<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
@EnableAspectJAutoProxy(exposeProxy = true)
public class Application {
}
总结
往期推荐
自定义注解!绝对是程序员装逼的利器!!
Oracle慌了!华为终于对JDK下手了!
美国大选的背后,黑客"粉丝"竟然有这些饭圈骚操作!
本文由“壹伴编辑器”提供技术支
直面Java第329期:哪个命令可以监控虚拟机各种运行状态信息?
深入并发第013期:拓展synchronized——锁优化