Cannot subclass final class class com.sun.proxy.$Proxy16

2016年05月04日 19:10:58

阅读数:15028

背景

这个错误是我在使用AOP动态切换数据库,实现数据库的读写分离的时候出现的问题,使用到的系统环境是:

<spring.version>3.2.6.RELEASE</spring.version> <mybatis.version>3.2.4</mybatis.version> <mybatis-spring.version>1.1.1</mybatis-spring.version>
  • 1
  • 2
  • 3

使用的代码

执行切点的代码是:

package com.xuliugen.choosedb.demo.aspect;import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.stereotype.Component; /** * 切换数据源(不同方法调用不同数据源) */ @Aspect @Component @EnableAspectJAutoProxy(proxyTargetClass = true) public class DataSourceAspect { protected Logger logger = LoggerFactory.getLogger(this.getClass()); //这个包是存放MyBatis的sql的包 @Pointcut("execution(* com.xuliugen.choosedb.demo.mybatis.dao.*.*(..))") public void aspect() { } /** * 配置前置通知,使用在方法aspect()上注册的切入点 */ @Before("aspect()") public void before(JoinPoint point) { String className = point.getTarget().getClass().getName(); String method = point.getSignature().getName(); logger.info(className + "." + method + "(" + StringUtils.join(point.getArgs(), ",") + ")"); try { for (String key : ChooseDataSource.METHOD_TYPE_MAP.keySet()) { for (String type : ChooseDataSource.METHOD_TYPE_MAP.get(key)) { if (method.startsWith(type)) { DataSourceHandler.putDataSource(key); } } } } catch (Exception e) { e.printStackTrace(); } } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

代码的整体意思就说获取配置文件中的读、写数据库和进行Aop的方法(在下边的配置文件中可以看到),DataSourceHandler是一个存放数据源的Handler。

配置文件如下:

<!-- 配置动态分配的读写 数据源 --><bean id="dataSource" class="com.xuliugen.choosedb.demo.aspect.ChooseDataSource" lazy-init="true"> <property name="targetDataSources"> <map key-type="java.lang.String" value-type="javax.sql.DataSource"> <!-- write --> <entry key="write" value-ref="writeDataSource"/> <!-- read --> <entry key="read" value-ref="readDataSource"/> </map> </property> <property name="defaultTargetDataSource" ref="writeDataSource"/> <property name="methodType"> <map key-type="java.lang.String"> <!-- read --> <entry key="read" value=",get,select,count,list,query"/> <!-- write --> <entry key="write" value=",add,create,update,delete,remove,"/> </map> </property> </bean> //这里省去读写数据源的配置
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

运行的错误信息

主要错误信息如下:

Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy16]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy16 at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:217) at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:111) at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:477) at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:362) at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:322) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:409) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.postProcessObjectFromFactoryBean(AbstractAutowireCapableBeanFactory.java:1655) at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:162) ... 70 more Caused by: java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy16 at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:446) at org.springframework.cglib.transform.TransformingClassGenerator.generateClass(TransformingClassGenerator.java:33) at org.springframework.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25) at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216) at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:377) at org.springframework.cglib.proxy.Enhancer.create(Enhancer.java:285) at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:205) ... 77 more
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

解决的过程:

Cannot subclass final class class com.sun.proxy.$Proxy16
  • 1

这句错误的原因很好理解,就是一个final 不可以被继承了,即final类不能子类化,因此不能代理proxy。

http://stackoverflow.com/上的一个回答,

You are not injecting an interface so you need to use CGLIB proxies, the spring reference manual states:Spring AOP defaults to using standard J2SE dynamic proxies for AOP proxies. This enables any interface (or set of interfaces) to be proxied. Spring AOP can also use CGLIB proxies. This is necessary to proxy classes, rather than interfaces. CGLIB is used by default if a business object does not implement an interface. As it is good practice to program to interfaces rather than classes, business classes normally will implement one or more business interfaces. Spring has decided to use a J2SE proxy (com.sun.proxy.$Proxy57) probably because CrudService implements an interface. To force the use of CGLIB you can tweak your XML: <aop:aspectj-autoproxy proxy-target-class="true"/>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Spring AOP can also use CGLIB proxies. This is necessary to proxy classes, rather than interfaces. 可以看出,在默认的情况下如果一个业务类没有继承接口的话是会使用CGLIB 的代理方式。CGLib是不能代理final类,或代理被final,private修饰的方法,cglib面对具体类代理,不能是接口。jdk的代理面向的是接口代理。因此如果你的业务类中没有使用到接口,而是直接使用类的方式,那么在进行 @Autowired或者@Inject的时候会出现错误。

两种的区别:java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换
  • 1
  • 2
  • 3

如何强制使用CGLIB实现AOP? 
* 在spring配置文件中加入

JDK动态代理和CGLIB字节码生成的区别? 
* JDK动态代理只能对实现了接口的类生成代理,而不能针对类 
* CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 
因为是继承,所以该类或方法最好不要声明成final


关于Spring的AOP代理方式,详细可以参考:http://blog.csdn.net/caomiao2006/article/details/51295158

http://blog.csdn.net/caomiao2006/article/details/51297443


他这里提到的解决方式在配置文件中加入:

<aop:aspectj-autoproxy proxy-target-class="true"/>
  • 1

可以看出我在DataSourceAspect 类上已经加入@EnableAspectJAutoProxy(proxyTargetClass = true) 的注解,效果是一样的的,因此这种方式不符合我遇到的问题。

因此,如果你在配置文件中进行了配置(<aop:aspectj-autoproxy proxy-target-class="true"/>),并且按照了Spring AOP 提供的代理方式,那么,这种方式是不可以解决的。

切换Spring版本解决问题

可以看出,我使用到的版本是3.2.6.RELEASE,查找相关资料发现,从Spring3.2以后,spring框架本身不在需要cglib这个jar包了,因为cjlib.jar已经被spring项目的jar包集成进去。为了防止项目中其他对cglib版本依赖不一样的冲突。

根据这个,想到了切换版本,然后将Spring的版本切换到了4.2.5.RELEASE 再次测试,正常运行,错误不见了。

可以初步的得到是由于版本的问题造成了这个错误的出现,因此对于这个问题可以参考上述的两种解决方式去解决实际的问题,希望能够对你的问题有所帮助。

转载于:https://www.cnblogs.com/javaboy2018/p/9138598.html

Cannot subclass final class class com.sun.proxy.$Proxy16相关推荐

  1. Cannot subclass final class class com.sun.proxy.$Proxy94

    背景 两个代码分支A.B,AB单独都能正常启动. 其中B分支进行了日志相关的改造,其中有一个点改动是 <aop:aspectj-autoproxy proxy-target-class=&quo ...

  2. Cannot subclass final class org.springframework.boot.autoconfigure.AutoConfigurationPackages

    自己写aop例子时遇到报错如下: Exception in thread "main" org.springframework.beans.factory.BeanCreation ...

  3. spring的动态代理,碰到了一个类型转换的问题:java.lang.ClassCastException: com.sun.proxy.$Proxy16 cannot be cast to com.

    spring的动态代理,碰到了一个类型转换的问题: java.lang.ClassCastException: com.sun.proxy.$Proxy16 cannot be cast to com ...

  4. AOP 注入失败的问题

    启用了AOP 后,报这样的类似错误: Error creating bean with name 'bpmpSysUserService': Injection of autowired depend ...

  5. 关于异常:警告: Exception encountered during context initialization - cancelling refresh attempt

    警告: Exception encountered during context initialization - cancelling refresh attempt: org.springfram ...

  6. Spring AOP 概念及动态代理模式

    Spring AOP 概念及动态代理模式 文章目录 Spring AOP 概念及动态代理模式 1 AOP 的概念及相关术语 2 AOP 作用 3 AOP 原理概述 3.1 JDK 动态代理(Proxy ...

  7. 深入理解Java Proxy和CGLIB动态代理原理

    点击上方关注,每天进步一点点 动态代理在Java中有着广泛的应用,比如Spring AOP,Hibernate数据查询.测试框架的后端mock.RPC,Java注解对象获取等.静态代理的代理关系在编译 ...

  8. 用java怎么实现数据库_用Java实现数据库应用系统

    package skydev.modules.data; public final class SqlServerConnectionFactory extends ConnectionFactory ...

  9. Java Proxy和CGLIB动态代理原理

    动态代理在Java中有着广泛的应用,比如Spring AOP,Hibernate数据查询.测试框架的后端mock.RPC,Java注解对象获取等.静态代理的代理关系在编译时就确定了,而动态代理的代理关 ...

最新文章

  1. windows配置maven环境并换源
  2. python进制转化大全
  3. 织梦?php?调用栏目,dedecms列表页内容页模板调用上一个栏目下一个栏目方法
  4. 【机器视觉】 endtry算子
  5. python学习-38迭代器和生成器
  6. 创立微积分的两场风波
  7. 基于Redis实现简单的分布式锁
  8. java后台生成分页_Java实现分页的前台页面和后台代码
  9. Mac如何修改文件默认打开方式?
  10. [Vue CLI 3] 环境变量和模式配置实践与源码分析
  11. 广东工业大学通信原理复习笔记第六章数字信号的基带传输(思维导图)含链接和习题
  12. win11电脑快捷键
  13. 数据治理——如何处理“脏数据”
  14. 计算机网络技术试题 中职,计算机网络技术试题(附答案)中等职业学校.doc
  15. veu3路由的安装和使用
  16. mysql 定时任务 每月15号执行
  17. ESP32 触摸传感器应用方案简介
  18. c# ffmpeg视频转换
  19. Pipeline流水线-通过Jenkinsfile构建任务
  20. 区块链学习8:超级账本项目Fabric中的背书、背书节点、背书策略、背书签名

热门文章

  1. SQL63 刷题通过的题目排名
  2. 怎么windows升级?windows版本升级?
  3. 一个人越来越沉默,即便是对着家人也无话可说,这究竟是怎么了?
  4. 辞职在家全职炒股需要什么条件?
  5. 难道早上起床后就一定要喝一杯白开水吗?
  6. 直播电商只能卖便宜货吗?
  7. python入门——P49乱入:生成器
  8. 死锁的处理策略——避免死锁
  9. python 中 print 函数用法总结
  10. sp_help用法_sp_updatestats概述和用法