闽公网安备 35020302035485号
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() 单元测试方法,就可以看到控制台会打印切面中的方法了。