spring基于cglib实现aop时是否可以支持一个对象内部方法间的嵌套代理
问答哪里没有人理,放在这里试试吧。。。
悬赏:5 发布时间:2008-12-31 提问人:jef (初级程序员)
网上的资料总是说spring的aop功能不支持对象内部方法间的嵌套代理。
不过今天试了一下,在不使用spring框架的时候,直接调用cglib的api,是可以实现一个对象内部方法间的嵌套代理的。
那么。。。为什么总说spring不支持一个实例方法间的嵌套代理呢。
如果强制spring使用cglib后可以实现嵌套代理,那么spring又是如何避免一个server内部方法间的事务的嵌套呢。
有点疑惑。。。望指点。。。:)
问题补充:
感谢netfork的关注,贴出cglib的测试代码,测试代码改自论坛中另外一个介绍cglib使用的帖子。
1)被代理类findInfo方法调用findInfo2方法
package x.y.aop.cglib;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;public class StudentInfoServiceImpl {
protected final Log logger = LogFactory.getLog(getClass()); public void findInfo(String name){ logger.info("你目前输入的名字是:"+name); //StudentInfoServiceImpl类内部调用! findInfo2(); logger.info("complete method findInfo"); } public void findInfo2(){ logger.info("i'm in findinfo2!!!"); }
}
2)cglib拦截类
package x.y.aop.cglib;import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;public class AOPInstrumenter implements MethodInterceptor {
protected final Log logger = LogFactory.getLog(getClass()); private Enhancer enhancer = new Enhancer(); public Object getInstrumentedClass(Class clz) { enhancer.setSuperclass(clz); enhancer.setCallback(this); return enhancer.create(); } public Object intercept(Object o, Method method, Object[] args, MethodProxy proxy) throws Throwable { logger.info("进入代理 方法:" + method.getName()); logger.info("开始执行原始方法:" + method.getName()); Object result = proxy.invokeSuper(o, args); logger.info("退出代理 方法:" + method.getName()); return result; }
}
3)main方法
package x.y.aop.cglib;public class main {
public static void main(String[] args) { AOPInstrumenter instrumenter = new AOPInstrumenter(); StudentInfoServiceImpl studentInfo = (StudentInfoServiceImpl)instrumenter.getInstrumentedClass(StudentInfoServiceImpl.class); studentInfo.findInfo("阿飞"); }
}
4)log日志输入
main - 进入代理 方法:findInfo
main - 开始执行原始方法:findInfo
main - 你目前输入的名字是:阿飞
main - 进入代理 方法:findInfo2
main - 开始执行原始方法:findInfo2
main - i'm in findinfo2!!!
main - 退出代理 方法:findInfo2
main - complete method findInfo
main - 退出代理 方法:findInfo
这个测试可以说明cglib能实现同一对象方法级的嵌套拦截了吧
如果有一天google能搜到此篇文章,为了给寻找答案的人一个交待,在这里再补上一段。
经过昨天和楼主的讨论,总算把这个问题基本弄清楚了。
纯粹用CGLIB来代理时,确实会出现嵌套代理的情况,package/protected/public方法均可能互相嵌套。
但是通过Spring来借助于CGLIB实现AOP时,就不会出现嵌套代理的情况。
原因是Spring使用CGLIB时,只是用了一个代理的壳,来达到同JDK代理同样的效果,在调用目标对象的虚拟子类对象的方法时,通过回调方法,实际上还是调用的目标对象的真身,并没有调用子类对象的父类方法,由于调用的是目标对象(实实在在的对象)的方法,所以在这个方法里再次调用其他方法时,就不会被代理到了,因此就不会产生嵌套代理的情况。
关于AOP的CGLIB的较完整的分析过程,可以参照下面的分析。
[url]http://netfork.iteye.com/blog/286215[/url]
似乎有点理解楼主的意思了。
下面的文章有说到动态代理情况下的AOP是不支持嵌套代理的。
[url]http://www.iteye.com/topic/40553[/url]
该文中也隐约提到了CGLIB代理的情况。根据我的理解(不定对不对,我只是前段Debug个Spring和CBLIB的源码,有段时间了,也没功夫再Debug了),如果换作CGLIB,CGLIB会虚拟一个子类作为代理对象,这个虚拟生成的子类中肯定会重截所有的public方法,package/protected的,我不太清楚,private的方法没有重载的必要。如果想彻底弄明白,只要Debug个一下Spring和CGLIB的源码应该就能弄清楚。
这样的话,如果你是在public方法中调public方法,通过AOP以后,调用过程就是这样的:
子类(CGLIB的虚拟生成类)方法A->父类(实际类)方法A->子类方法B->父类方法B
从这个过程来看,你所谓的AOP嵌套肯定会发生的,因为在父类方法B被子类的方法B代理过了。
上文分析只是public方法时发生的情况,通常情况下,public方法再调用本类中的public方法的可能性并不大,如果存在,也可能是设计上的问题。
所以,从这个意义上讲,只要public方法中调用的不是public方法方法留给楼主验证了(package/protected),事务的嵌套不可能会发生;而且即使是事务aop,也只是对特殊命名的方法进行事务控制,而不会是所有的方法都需要事务控制吧。所以,事务嵌套的情况是完全可以避免的。
刚刚看了补充,跟我想的一致的,果然是public方法调本类的public方法,这种程序,一般是很少碰到的,如果出现,应该是设计的问题。而且public方法调本类public方法,在事务处理中就更难发生了。
总结:楼主举的案例确实是会存在嵌套的情况,但真实的系统设计中,不会出现这种情况。分层结构和通常系统的设计思路,完全可以避免掉这种情况的出现。
楼主说的“对象内部方法”是指的私有方法吗?
能不能把测试的代码贴上来看看?大家一起研究下。