春哥大魔王的博客

春哥大魔王的博客

我们知道Spring对于AOP实现有两种方法,如果类是接口实现类,则采用JDK动态代理实现AOP。如果类没有实现接口,则采用cglib生成子类做增强,以实现代理类的目的,其实运行时找到的是这个代理类,而不是原类。

所以在一个代理类中调用内部的方法,是不是再走AOP逻辑的,那有什么好的方法可以解决这种问题吗?

基于上面的思路有两种解决办法

方法一:直接从BeanFactory中获取再次代理Bean 示例代码如下:

@Service
public class DemoService implements IDemoService {

    @Autowired
    private ApplicationContext context;

    public String demoHello(){
        System.out.println("hello");
        final IDemoService bean = context.getBean(IDemoService.class);
        bean.normalHello();
        return "hello";
    }
}

即继续调用代理类的normalHello()方法。

方法二:从AopContext中获取代理Bean

SpringAop有一个配置参数exposeProxy 如果配置为true ,可以让代理对象的方法被调用时把代理对象放入AopContext,这个配置的定义如下(ps:看看这个配置的注释说明):

//org.springframework.context.annotation.EnableAspectJAutoProxy
/**
 * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
 * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
 * Off by default, i.e. no guarantees that {@code AopContext} access will work.
 * @since 4.3.1
 */
boolean exposeProxy() default false;

所以代码还可以这样写:启动类EnableAspectJAutoProxy注解改为

@EnableAspectJAutoProxy(exposeProxy = true)
DemoService 类demoHello()方法改为:

    public String demoHello(){
        System.out.println("hello");
        final IDemoService bean = (IDemoService) AopContext.currentProxy();
        bean.normalHello();
        return "hello";
    }

exposeProxy 属性如何生效的?

在这里拓展一点点,关于Aop有两个很重要的方法, 代理类增强方法被调用时会进入这两个个方法中的其中一个,基于代理方式:

CglibAopProxy.DynamicAdvisedInterceptor#intercept //Cglib代理方式
JdkDynamicAopProxy#invoke //JDK 代理方式

这两个被代理类的方法在执行的时候都有这么一段代码:

if (this.advised.exposeProxy) {
    // Make invocation available if necessary.
    oldProxy = AopContext.setCurrentProxy(proxy);
    setProxyContext = true;
}

因为进入了intercept或者invoke方法,那么表示正在调用proxy这个代理类的某个方法,那么就把代理类放入Aop 上下文。

当然最好的一种方法,是将不同的功能放到不同的类里面,这样调用起来就不是调用当前类了。

03-09 00:34