记录下这个事情。
在我的设想中,同类方法的调用也可以走代理,毕竟都是一个类了,xxx()调用肯定走的是代理的方法,调试后发现跟我想的不一样,所以看了一下源码发现了这个事情。
结论是:Spring AOP最终执行的方法的对象是代理的目标对象,而不是生成的代理类对象
下面是Spring的CglibAopProxy
源码:
@Override
protected Object invokeJoinpoint() throws Throwable {
if (this.methodProxy != null) {
return this.methodProxy.invoke(this.target, this.arguments);
}
else {
return super.invokeJoinpoint();
}
}
如果你使用断点访问,很直观的就能看到,这个是你代理的目标对象。
再来看看Cglib的MethodInterceptor
的intercept
方法
/**
*
* @param obj 表示要进行增强的对象
* @param method 表示拦截的方法
* @param args 参数数组
* @param methodProxy 表示对方法的代理,规避反射调用
* @return 执行结果
* @throws Throwable 异常
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable
在intercept
方法中,obj
是代理后的对象,不是你的目标对象,所以Spring在构建MethodInterceptor
对象时把目标对象保存,然后在处理完成所有的增强后使用目标对象调用方法。
假设你不使用目标对象调用方法,调用同类方法会走代理实现,看下方的代码和具体的结果
public class TestCglib {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserDao.class);
enhancer.setCallback(new LogInterceptor());
UserDao userDao = (UserDao) enhancer.create();
userDao.m1();
}
public static class UserDao {
public void m1(){
this.m2();
}
protected void m2(){}
}
public static class LogInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
String methodName = method.getName();
System.out.println("调用方法" + methodName +"之【前】的日志处理");
Object result = methodProxy.invokeSuper(obj, objects);
System.out.println("调用方法" + methodName +"之【后】的日志处理");
return result;
}
}
}
结果:
调用方法m1之【前】的日志处理
调用方法m2之【前】的日志处理
调用方法m2之【后】的日志处理
调用方法m1之【后】的日志处理
总结
我的想法是没问题的,但在Spring中有特定的规则?我不确定是不是Spring做这样的处理是为了防止递归调用还是其他原因。最终我在本类中获取本类的bean,然后用这个bean调用方法