我们知道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 上下文。
当然最好的一种方法,是将不同的功能放到不同的类里面,这样调用起来就不是调用当前类了。