spring基于cglib实现aop时是否可以支持一个对象内部方法间的嵌套代理

本文探讨了CGLIB库在实现对象内部方法间嵌套代理的能力,并通过示例代码展示了这一过程。同时,文章解释了为何Spring AOP不支持此类嵌套代理,以及Spring如何利用CGLIB避免服务器内部方法间的事务嵌套。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

网上的资料总是说spring的aop功能不支持对象内部方法间的嵌套代理。
不过今天试了一下,在不使用spring框架的时候,直接调用cglib的api,是可以实现一个对象内部方法间的嵌套代理的。
那么。。。为什么总说spring不支持一个实例方法间的嵌套代理呢。
如果强制spring使用cglib后可以实现嵌套代理,那么spring又是如何避免一个server内部方法间的事务的嵌套呢。
有点疑惑。。。望指点。。。:)
问题补充:
感谢netfork的关注,贴出cglib的测试代码,测试代码改自论坛中另外一个介绍cglib使用的帖子。

1)被代理类findInfo方法调用findInfo2方法

Java代码 复制代码
  1. package x.y.aop.cglib;   
  2.   
  3. import org.apache.commons.logging.Log;   
  4. import org.apache.commons.logging.LogFactory;   
  5.   
  6. public class StudentInfoServiceImpl {   
  7.   
  8.     protected final Log logger = LogFactory.getLog(getClass());   
  9.        
  10.     public void findInfo(String name){   
  11.         logger.info("你目前输入的名字是:"+name);   
  12.         //StudentInfoServiceImpl类内部调用!   
  13.         findInfo2();   
  14.         logger.info("complete method findInfo");   
  15.     }   
  16.        
  17.     public void findInfo2(){   
  18.         logger.info("i'm in findinfo2!!!");   
  19.     }   
  20.        
  21.        
  22. }  
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拦截类

Java代码 复制代码
  1. package x.y.aop.cglib;   
  2.   
  3. import java.lang.reflect.Method;   
  4.   
  5. import net.sf.cglib.proxy.Enhancer;   
  6. import net.sf.cglib.proxy.MethodInterceptor;   
  7. import net.sf.cglib.proxy.MethodProxy;   
  8.   
  9. import org.apache.commons.logging.Log;   
  10. import org.apache.commons.logging.LogFactory;   
  11.   
  12. public class AOPInstrumenter implements MethodInterceptor {   
  13.   
  14.     protected final Log logger = LogFactory.getLog(getClass());   
  15.   
  16.     private Enhancer enhancer = new Enhancer();   
  17.   
  18.     public Object getInstrumentedClass(Class clz) {   
  19.         enhancer.setSuperclass(clz);   
  20.         enhancer.setCallback(this);   
  21.         return enhancer.create();   
  22.     }   
  23.   
  24.     public Object intercept(Object o, Method method, Object[] args,   
  25.             MethodProxy proxy) throws Throwable {   
  26.         logger.info("进入代理 方法:" + method.getName());   
  27.         logger.info("开始执行原始方法:" + method.getName());   
  28.         Object result = proxy.invokeSuper(o, args);   
  29.         logger.info("退出代理 方法:" + method.getName());   
  30.         return result;   
  31.     }   
  32.   
  33. }  
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方法

Java代码 复制代码
  1. package x.y.aop.cglib;   
  2.   
  3. public class main {   
  4.   
  5.     public static void main(String[] args) {   
  6.         AOPInstrumenter instrumenter = new AOPInstrumenter();   
  7.         StudentInfoServiceImpl studentInfo = (StudentInfoServiceImpl)instrumenter.getInstrumentedClass(StudentInfoServiceImpl.class);   
  8.         studentInfo.findInfo("阿飞");   
  9.     }   
  10. }  
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日志输入

Java代码 复制代码
  1. main - 进入代理 方法:findInfo   
  2. main - 开始执行原始方法:findInfo   
  3. main - 你目前输入的名字是:阿飞   
  4. main - 进入代理 方法:findInfo2   
  5. main - 开始执行原始方法:findInfo2   
  6. main - i'm in findinfo2!!!   
  7. main - 退出代理 方法:findInfo2   
  8. main - complete method findInfo   
  9. 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
### Spring @Transactional 注解式事务原理 #### 1. **核心概念** `@Transactional` 是 Spring 提供的一种声明式事务管理方式,它通过 AOP(面向切面编程)技术实现了事务的自动化管理和配置。当开发者在一个方法上标注 `@Transactional` Spring 将自动为其生成一个代理对象,并在该方法执行前后完成事务的相关操作。 #### 2. **工作流程** 以下是基于引用内容和专业知识总结的 `@Transactional` 工作机制: - 当应用程序启动Spring 容器会扫描带有 `@EnableTransactionManagement` 或 `<tx:annotation-driven>` 的配置类/文件[^3]。 - 如果检测到这些配置,Spring 会在 IOC 容器中注册两个重要的 Bean: - **AutoProxyRegistrar**: 这是一个后置处理器,负责为符合条件的目标对象创建动态代理实例。 - **ProxyTransactionManagementConfiguration**: 实现了事务切面的核心逻辑,定义了如何处理事务边界。 - 动态代理分为两种形式:JDK 动态代理(针对接口)和 CGLIB 字节码增强(针对无接口的情况)。无论哪种方式,最终都会生成一个代理对象来拦截目标方法的调用[^2]。 #### 3. **具体执行过程** 假设有一个被 `@Transactional` 标记的方法被执行,其内部工作机制可以分解如下: ##### (1)事务初始化阶段 - 在代理对象调用实际业务方法之前,Spring 会先判断当前线程是否存在已有的事务上下文。如果没有,则根据指定的事务属性(如隔离级别、传播行为等),通过事务管理器 (`PlatformTransactionManager`) 创建一个新的事务并绑定到当前线程的 `ThreadLocal` 中[^5]。 ```java // 设置 auto-commit 属性为 false 并保存连接至 ThreadLocal Connection conn = dataSource.getConnection(); conn.setAutoCommit(false); TransactionSynchronizationManager.bindResource(dataSource, new ConnectionHolder(conn)); ``` ##### (2)方法执行期 - 接下来进入真正的业务逻辑部分,在此过程中可能会涉及多个 SQL 操作。由于所有的数据库交互都共享同一个 `ThreadLocal` 绑定的数据源资源,因此能够保证一致性[^4]。 ##### (3)事务提交或回滚 - 方法正常返回触发 commit;如果抛出了未被捕获的异常则触发 rollback。这一步骤依赖于默认规则或者自定义策略决定哪些类型的异常应该引起回滚。 ```java try { // 执行业务逻辑... } catch (Exception e) { transaction.rollback(); // 出错情况下回滚 throw e; } finally { if (!transaction.isRollbackOnly()) { transaction.commit(); // 成功完成后提交 } } ``` #### 4. **关键组件解析** - **TransactionInterceptor**: 作为主要的事务拦截器之一,它的职责是在每次请求到达目标服务层方法前检查是否有合适的事务存在。如果有必要的话就新启一项新的事务或将现有事务延续下去[^1]。 - **TransactionSynchronizationManager**: 此工具类提供了静态方法用来管理各种同步状态信息,比如存储当前活动中的事务关联的对象列表等等。 - **ThreadLocal**: 利用 Java 内建的 `ThreadLocal` 变量机制确保每个独立运行的任务都有自己私有的副本数据结构,从而避免多线程环境下的竞争条件问题。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值