SpringAOP中com.sun.proxy.$Proxy14 cannot be cast to com.spring.beans.aop.Computerimpl报错及分析解决

本文介绍了一个关于Spring AOP中代理类类型转换的问题及解决方案。在使用Spring AOP时,尝试直接将代理对象转换为具体实现类而非接口时会遇到类型转换异常。文章给出了正确的做法,即通过接口进行转换,避免错误。

今天在写SpringAop时报了com.sun.proxy.$Proxy14 cannot be cast to com.spring.beans.aop.Computerimpl,代码如下:

        ApplicationContext ac=new ClassPathXmlApplicationContext("IOC_scan.xml");
	Computerimpl com=(Computerimpl) ac.getBean("computerimpl");
	System.out.println(com.add(1, 2));

其中红色部分为报错原因,不能用接口的实现类(Computerimpl)来转换Proxy的实现类,它们是同级,应该用共同的接口来转换。将红色代码修改为:

Computer com=(Computer) ac.getBean("computerimpl");

编译后没有该报错了。

引用:点击打开链接

<think> 我们正在解决一个典型的Spring AOP代理问题。异常信息`java.lang.NoSuchMethodException: com.sun.proxy.$Proxy68.getRmsPackageClinicalDrugsStockList()`表明,Spring生成的代理对象(这里是JDK动态代理)试图调用一个不存在的方法。这通常发生在基于接口的代理(JDK动态代理)时,而目标方法没有在接口中声明。 根据引用[1][2][3]的内容,我们可以总结出以下关键点: 1. 当使用JDK动态代理(基于接口)时,代理对象只能调用接口中声明的方法。 2. 如果目标类没有实现接口,或者调用的方法不在接口中,则需要使用CGLIB代理(基于类的代理)。 3.Spring配置中,可以通过设置`proxy-target-class="true"`来强制使用CGLIB代理。 解决步骤: ### 1. 检查目标方法是否在接口中声明 首先,确认出现异常的方法`getRmsPackageClinicalDrugsStockList()`是否在对应的Service接口中声明。如果该方法是在实现类中直接添加的(没有在接口中声明),那么当使用JDK动态代理时,代理对象将无法找到该方法。 ### 2. 修改Spring配置以使用CGLIB代理 如果方法确实不在接口中声明,我们可以通过配置强制Spring使用CGLIB代理,这样代理对象就可以继承目标类,从而调用不在接口中的方法。 在Spring的配置文件中(如applicationContext.xml),找到声明事务管理或AOP代理的相关部分,添加`proxy-target-class="true"`。 例如,对于声明式事务管理,修改如下: ```xml <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/> ``` 或者,对于使用`DefaultAdvisorAutoProxyCreator`的情况(如引用[2]所示): ```xml <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> <property name="proxyTargetClass" value="true"/> </bean> ``` ### 3. 使用注解配置强制CGLIB代理 如果使用Java配置,可以在`@EnableTransactionManagement`注解中设置: ```java @EnableTransactionManagement(proxyTargetClass = true) ``` ### 4. 确保CGLIB库存在 使用CGLIB代理需要确保项目中包含了CGLIB库(如cglib.jar)。如果使用Maven,可以添加依赖: ```xml <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency> ``` ### 5. 检查方法访问权限 确保被调用的方法具有public访问权限。因为Spring代理只能代理public方法。 ### 6. 避免自调用问题 如果是在同一个类中调用另一个被事务注解的方法,由于自调用(即通过this调用)会绕过代理,导致事务不生效,也可能出现类似问题。此时,应该通过AopContext获取当前代理对象来调用,或者将方法拆分到不同的类中。 ### 示例代码 假设出现问题的代码类似于: ```java @Service public class DrugServiceImpl implements DrugService { // 假设这个getRmsPackageClinicalDrugsStockList方法是在实现类中新增的,没有在DrugService接口中声明 public List<RmsPackageClinicalDrugsStock> getRmsPackageClinicalDrugsStockList() { // ... } } ``` 在调用时: ```java @Controller public class SomeController { @Autowired private DrugService drugService; public void someMethod() { // 如果drugService是JDK代理,而getRmsPackageClinicalDrugsStockList不在DrugService接口中,则这里会抛异常 drugService.getRmsPackageClinicalDrugsStockList(); } } ``` ### 总结 通过以上步骤,我们可以解决由于代理方式导致的方法找不到异常。核心在于统一代理方式,确保方法在接口中声明或者使用CGLIB代理。 §§相关问题§§ 1. 如何判断Spring当前使用的是JDK代理还是CGLIB代理? 2.Spring Boot中如何配置使用CGLIB代理? 3. 为什么JDK动态代理要求方法必须在接口中声明? 4. 使用CGLIB代理有什么局限性? </think> ### 解决 `java.lang.NoSuchMethodException: com.sun.proxy.$Proxy68.getRmsPackageClinicalDrugsStockList()` 异常 #### 问题原因分析 该异常是由于 Spring AOP 代理机制与方法可见性冲突导致: 1. **JDK 动态代理限制** Spring 默认使用 JDK 动态代理(基于接口),只能代理接口中声明的方法[^3]。若目标方法未在接口中定义,代理对象无法访问该方法。 2. **CGLIB 代理未启用** 当类未实现接口或需要代理非接口方法时,必须启用基于类的 CGLIB 代理[^1][^3]。 #### 解决方案 ##### 方法 1:强制启用 CGLIB 代理(推荐) 在 Spring 配置中添加: ```xml <!-- applicationContext.xml --> <aop:aspectj-autoproxy proxy-target-class="true"/> ``` 或 ```xml <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"> <property name="proxyTargetClass" value="true"/> </bean> ``` **效果**: ✅ 代理目标类而非接口 ✅ 支持非接口方法调用[^3] ✅ 需添加 CGLIB 依赖 ##### 方法 2:确保方法在接口中声明 检查 Service 接口是否包含目标方法: ```java // 正确示例 public interface DrugService { List<RmsPackageClinicalDrugsStock> getRmsPackageClinicalDrugsStockList(); // 必须在接口声明 } @Service public class DrugServiceImpl implements DrugService { @Override // 确保实现接口方法 public List<RmsPackageClinicalDrugsStock> getRmsPackageClinicalDrugsStockList() { // 实现逻辑 } } ``` **效果**: ✅ 兼容 JDK 动态代理 ⚠️ 需修改接口定义 ##### 方法 3:检查注解位置 移除抽象类上的无效注解: ```java // 错误示例(会导致代理异常[^1]) @Transactional // ❌ 抽象类上无效 public abstract class BaseAction { // ... } // 正确做法:仅在具体类添加注解 @Service @Scope("prototype") public class DrugAction extends BaseAction { @Transactional // ✅ 具体类生效 public void recycle() { ... } } ``` #### 配置验证 检查代理类型: ```java @Autowired private ApplicationContext ctx; public void checkProxyType() { Object bean = ctx.getBean("drugService"); System.out.println("代理类型: " + bean.getClass()); // 应输出:class com.example.DrugService$$EnhancerBySpringCGLIB$$ } ``` #### 完整修复流程 1. 添加 Maven 依赖: ```xml <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency> ``` 2. 配置 Spring XML: ```xml <beans> <aop:aspectj-autoproxy proxy-target-class="true"/> <context:component-scan base-package="com.yourpackage"/> </beans> ``` 3. 验证代理对象方法: ```java // 测试代码 DrugService proxy = ctx.getBean(DrugService.class); Method[] methods = proxy.getClass().getDeclaredMethods(); Arrays.stream(methods).forEach(m -> System.out.println("代理方法: " + m.getName()) ); // 应包含 getRmsPackageClinicalDrugsStockList ``` #### 典型错误场景排除 ```mermaid graph TD A[调用代理方法] --> B{方法是否在接口中?} B -->|是| C[JDK代理正常执行] B -->|否| D{是否启用CGLIB?} D -->|是| E[CGLIB代理正常执行] D -->|否| F[抛出NoSuchMethodException] F --> G[检查proxy-target-class配置] G --> H[添加proxy-target-class=true] ``` > **关键提示**:Spring Boot 用户可在启动类添加: > ```java > @SpringBootApplication > @EnableTransactionManagement(proxyTargetClass = true) // 强制CGLIB > public class Application { ... } > ``` [^1]: 抽象类上的 @Transactional 会导致代理异常 [^2]: 需显式配置 DefaultAdvisorAutoProxyCreator [^3]: proxy-target-class 控制代理类型选择
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值