网上的资料总是说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!!!");
- }
- }
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;
- }
- }
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("阿飞");
- }
- }
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
main - 进入代理 方法:findInfo
main - 开始执行原始方法:findInfo
main - 你目前输入的名字是:阿飞
main - 进入代理 方法:findInfo2
main - 开始执行原始方法:findInfo2
main - i'm in findinfo2!!!
main - 退出代理 方法:findInfo2
main - complete method findInfo
main - 退出代理 方法:findInfo
采纳的答案
2009-01-04 netfork (初级程序员)
如果有一天google能搜到此篇文章,为了给寻找答案的人一个交待,在这里再补上一段。
经过昨天和楼主的讨论,总算把这个问题基本弄清楚了。
纯粹用CGLIB来代理时,确实会出现嵌套代理的情况,package/protected/public方法均可能互相嵌套。
但是通过Spring来借助于CGLIB实现AOP时,就不会出现嵌套代理的情况。
原因是Spring使用CGLIB时,只是用了一个代理的壳,来达到同JDK代理同样的效果,在调用目标对象的虚拟子类对象的方法时,通过回调方法,实际上还是调用的目标对象的真身,并没有调用子类对象的父类方法,由于调用的是目标对象(实实在在的对象)的方法,所以在这个方法里再次调用其他方法时,就不会被代理到了,因此就不会产生嵌套代理的情况。
关于AOP的CGLIB的较完整的分析过程,可以参照下面的分析。
http://netfork.iteye.com/blog/286215
经过昨天和楼主的讨论,总算把这个问题基本弄清楚了。
纯粹用CGLIB来代理时,确实会出现嵌套代理的情况,package/protected/public方法均可能互相嵌套。
但是通过Spring来借助于CGLIB实现AOP时,就不会出现嵌套代理的情况。
原因是Spring使用CGLIB时,只是用了一个代理的壳,来达到同JDK代理同样的效果,在调用目标对象的虚拟子类对象的方法时,通过回调方法,实际上还是调用的目标对象的真身,并没有调用子类对象的父类方法,由于调用的是目标对象(实实在在的对象)的方法,所以在这个方法里再次调用其他方法时,就不会被代理到了,因此就不会产生嵌套代理的情况。
关于AOP的CGLIB的较完整的分析过程,可以参照下面的分析。
http://netfork.iteye.com/blog/286215