SpringBoot 业务的 Service 层方法 m1() 调用了同类中的 m2() 方法,注解 @Cacheable 此时在 m2(), 我们通过 this.m2() 方法时却不会走缓存而是直接进数据库了。这里还是动态代理中的代理对象的问题。

public void m1(){
// ...
this.m2();
// ... other code
}

@Cacheable(value = "cacheValue", key = "#root.methodName")
public User m2(){
return userMapper.selectAll();
}

在 SpringBoot 的 main 方法上开启 AspectJ 自动代理,内部配置都为 true.

@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
@EnableCaching
@SpringBootApplication

proxyTargetClass: 开启则启用基于父类的 CGLIB 代理,默认 false 走 Java 基于接口的动态代理。

exposeProxy: AOP 框架通过 ThreadLocal 公开此代理对象,可使用 AopContext 的静态方法获取对象,默认不开启。

参考源码可以看到,AopContext 类中定义了 ThreadLocal 作为静态常量:

public final class AopContext {

/**
* ThreadLocal holder for AOP proxy associated with this thread.
* Will contain {@code null} unless the "exposeProxy" property on
* the controlling proxy configuration has been set to "true".
* @see ProxyConfig#setExposeProxy
*/
private static final ThreadLocal<Object> currentProxy = new NamedThreadLocal<>("Current AOP proxy");

private AopContext() {
}

/**
* Try to return the current AOP proxy. This method is usable only if the
* calling method has been invoked via AOP, and the AOP framework has been set
* to expose proxies. Otherwise, this method will throw an IllegalStateException.
* @return the current AOP proxy (never returns {@code null})
* @throws IllegalStateException if the proxy cannot be found, because the
* method was invoked outside an AOP invocation context, or because the
* AOP framework has not been configured to expose the proxy
*/
public static Object currentProxy() throws IllegalStateException {
Object proxy = currentProxy.get();
if (proxy == null) {
throw new IllegalStateException(
"Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.");
}
return proxy;
}

然后,用上面的静态方法把我们之前的 this 对象换掉:

public void m1(){
// 获取 AOP 代理对象
YourService currentProxy = (YourService) AopContext.currentProxy();
currentProxy.m2();
// ... other code
}

此后的对象就是代理对象了。