public interface ProxyService { void proxy(); void testProxy(); } java复制代码@Service public class ProxyServiceImpl implements ProxyService { @Override public void proxy() { System.out.println("ProxyServiceImpl.proxy 方法被调用"); } @Override public void testProxy() { System.out.println("ProxyServiceImpl.testProxy 方法被调用"); proxy(); } }测试类:
@SpringBootTest public class ProxyApplicationTest { @Resource private ProxyService proxyService; @Test public void testProxy(){ proxyService.testProxy(); } }定义一个切面,用于验证获取代理对象是否生效:
@Component @Aspect public class ProxyAspect { @Pointcut("execution(* site.suncodernote.proxy.ProxyService.proxy())") void proxyServicePointCut(){ } //堆代码 duidaima.com @After("proxyServicePointCut()") public void jdkDivide(JoinPoint joinPoint){ System.out.println("---------------------jdkProxyServicePointCut切面生效了----------------"); } }运行测试类,你觉得结果会是什么?
ProxyServiceImpl.testProxy 方法被调用 ProxyServiceImpl.proxy 方法被调用为什么会这样呢?因为代理内部调用代理的其他方法时,直接调用可能会导致调用的是目标对象的方法,而不是经过增强的方法,所以也就没走切面。
@Service public class ProxyServiceImpl implements ProxyService { @Resource private ProxyService proxyService;
这种方式也能达到目的,但是有点不太好。
@Service public class ProxyServiceImpl implements ProxyService { @Resource private ObjectFactory<ProxyService> objectFactory; @Override public void proxy() { System.out.println("JDKProxyServiceImpl.proxy"); } @Override public void testProxy() { System.out.println("JDKProxyServiceImpl.testProxy"); // proxy(); ProxyService proxyService = objectFactory.getObject(); proxyService.proxy(); } }打印结果:
@EnableAspectJAutoProxy(exposeProxy = true)为什么默认情况下,Spring不会开启AopContext的支持呢?主要是考虑到性能问题。
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() { } /** * 获取当前代理对象 */ 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, and " + "ensure that AopContext.currentProxy() is invoked in the same thread as the AOP invocation context."); } return proxy; } @Nullable static Object setCurrentProxy(@Nullable Object proxy) { Object old = currentProxy.get(); if (proxy != null) { currentProxy.set(proxy); } else { currentProxy.remove(); } return old; } }可以看到,·当开启AopContext的支持时,Spring需要在每次方法调用时维护一个当前代理对象的线程本地变量 currentProxy。这会引入额外的内存开销和执行时开销,因为需要动态地确定当前调用是否处于AOP代理的上下文中。
@Override public void testProxy() { System.out.println("ProxyServiceImpl.testProxy 方法被调用"); // proxy(); ProxyService proxyService = (ProxyService) AopContext.currentProxy(); proxyService.proxy(); }再次调用ProxyApplicationTest#testProxy() 单元测试方法,就可以看到控制台会打印切面中的方法了。