`
summer_021
  • 浏览: 58015 次
  • 性别: Icon_minigender_1
  • 来自: 上海
最近访客 更多访客>>
社区版块
存档分类
最新评论

Spring使用AOP时ClassCastException问题

 
阅读更多
Spirng实现AOP采用动态代理还是CGLIB代理,两种方式如下:

1、Spring:自动选择。

如果有实现接口采用JDK动态代理
如果没有实现接口采用cglib代理
<aop:aspectj-autoproxy proxy-target-class="false"/>  


2、强制只用cglilb代理:
<aop:aspectj-autoproxy proxy-target-class="true"/>  


以下是JDK动态代理和CGLIB代理简单介绍

    JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理。
    CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB是高效的代码生成包,底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的,性能比JDK强。注意:cglib代理不能覆盖 final 方法! 在final方法前面后面加逻辑不行。

在默认情况下,如果一个目标对象如果实现了接口Spring则会选择JDK动态代理策略动态的创建一个接口实现类(动态代理类)来代理目标对象,可以通俗的理解这个动态代理类是目标对象的另外一个版本,所以这两者之间在强制转换的时候会抛出j ava.lang.ClassCastException。而所以在默认情况下,如果目标对象没有实现任何接口,Spring会选择CGLIB代理, 其生成的动态代理对象是目标类的子类,不会有ClassCastException异常

以下为网上摘录的:

Spring AOP部分使用JDK动态代理或者CGLIB来为目标对象创建代理。(建议尽量使用JDK的动态代理)

如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理。所有该目标类型实现的接口都将被代理。若该目标对象没有实现任何接口,则创建一个CGLIB代理。

如果你希望强制使用CGLIB代理,(例如:希望代理目标对象的所有方法,而不只是实现自接口的方法)那也可以。但是需要考虑以下问题:

    * 无法通知(advise)Final 方法,因为他们不能被覆写。
    * 你需要将CGLIB 2二进制发行包放在classpath下面,与之相较JDK本身就提供了动态代理

强制使用CGLIB代理需要将 <aop:config> 的 proxy-target-class 属性设为true:

<aop:config proxy-target-class="true">
...
</aop:config>

当需要使用CGLIB代理和@AspectJ自动代理支持,请按照如下的方式设置 <aop:aspectj-autoproxy> 的 proxy-target-class 属性:

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

而实际使用的过程中才会发现细节问题的差别,The devil is in the detail.

JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理。

CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB是高效的代码生成包,底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的,性能比JDK强。

Spring是依靠什么来判断采用哪种代理策略来生成AOP代理呢?以下代码就是Spring的判断逻辑
//org.springframework.aop.framework.DefaultAopProxyFactory   

    //参数AdvisedSupport 是Spring AOP配置相关类   

    public AopProxy createAopProxy(AdvisedSupport advisedSupport)   

            throws AopConfigException {   

        //在此判断使用JDK动态代理还是CGLIB代理   

        if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass()   

                || hasNoUserSuppliedProxyInterfaces(advisedSupport)) {   

            if (!cglibAvailable) {   

                throw new AopConfigException(   

                        "Cannot proxy target class because CGLIB2 is not available. "  

                                + "Add CGLIB to the class path or specify proxy interfaces.");   

            }   

            return CglibProxyFactory.createCglibProxy(advisedSupport);   

        } else {   

            return new JdkDynamicAopProxy(advisedSupport);   

        }   

    }


advisedSupport.isOptimize()与advisedSupport.isProxyTargetClass()默认返回都是false,所以在默认情况下目标对象有没有实现接口决定着Spring采取的策略,当然可以设置advisedSupport.isOptimize()或者advisedSupport.isProxyTargetClass()返回为true,这样无论目标对象有没有实现接口Spring都会选择使用CGLIB代理。所以在默认情况下,如果一个目标对象如果实现了接口Spring则会选择JDK动态代理策略动态的创建一个接口实现类(动态代理类)来代理目标对象,可以通俗的理解这个动态代理类是目标对象的另外一个版本,所以这两者之间在强制转换的时候会抛出java.lang.ClassCastException。而所以在默认情况下,如果目标对象没有实现任何接口,Spring会选择CGLIB代理, 其生成的动态代理对象是目标类的子类。

上说的是默认情况下,也可以手动配置一些选项使Spring采用CGLIB代理。

org.springframework.transaction.interceptor.TransactionProxyFactoryBean是org.springframework.aop.framework. ProxyConfig的子类,所以可以参照ProxyConfig里的一些设置如下所示,将optimize和proxyTargetClass任意一个设置为true都可以强制Spring采用CGLIB代理。

如果当需要使用CGLIB代理和@AspectJ自动代理支持,请按照如下的方式设置 <aop:aspectj-autoproxy> 的 proxy-target-class 属性:
<aop:aspectj-autoproxy proxy-target-class="true"/>

这样使用CGLIB代理也就不会出现前面提到的ClassCastException问题了,也可以在性能上有所提高,关键是对于代理对象是否继承接口可以统一使用。



Spring doc原文解释如下:
optimization will usually mean that advice changes won't  take effect after a proxy has been created. For this reason, optimization  is disabled by default。
分享到:
评论

相关推荐

    hibernate,struts,spring 常见错误信息

    在遇到这些问题时,开发者应检查相关配置文件,查看日志信息,理解错误堆栈,定位问题所在。同时,熟悉框架原理,了解其运行机制,可以帮助更快地解决问题。通过阅读官方文档、参与社区讨论和不断实践,可以提高处理...

    《MyEclipse 6 Java 开发中文教程》前10章

    10.5.2.4 用Spring 2.0 的aop和tx声明式配置解决事务提交问题 247 10.5.2.5 用Spring 2.0 的@Transactional标注解决事务提交问题(最佳方案) 251 10.5.2.6 使用 HibernateTemplate 实现分页查询 254 10.6 小结 255 ...

    这个就是我所说的有问题的

    10. **反射和动态代理**:反射允许程序在运行时操作类、接口和对象,而动态代理可以在运行时生成代理类,用于AOP(面向切面编程)和回调机制。 由于没有具体问题描述,以上只是对Java编程中可能出现的问题和知识点...

    交通银行Java笔试2.pdf

    Spring 框架提供了 AOP(Aspect-Oriented Programming)机制来实现面向方面编程,MethodInterceptor 是 Spring AOP 中的一个接口,用于实现around 通知。 2. JSP 生命周期中,jspInit() 方法只会运行一次,jsp...

    202310雪中悍刀行面试题

    代理模式是用于提供一个代理对象,例如 Spring 的 AOP。策略模式是用于提供一个算法接口,例如同一个接口有多种不同的实现类。 SQL 优化 SQL 优化是数据库性能优化的重要一步。常见的 SQL 优化方法包括使用索引、...

    Java开发手册(嵩山版)灵魂15问.zip

    1. **类型安全与泛型**:Java中的泛型是编程中的重要工具,用于确保类型安全,防止在运行时出现ClassCastException。手册可能会详细介绍泛型的使用规则、通配符和边界,以及如何在设计API时充分利用泛型的优势。 2....

    java面试问题汇总(非常全面)

    Spring AOP(Aspect Oriented Programming)提供了一种机制,用于分离横切关注点(如日志、安全、事务管理等)与核心业务逻辑。 #### 54. Spring最直接的特点?IOC - **Inversion of Control (IoC)**:控制反转,...

    java笔试面试题(含有笔试题,核心技术,重点知识,struts,hibernate,spring,eclipse)

    - **泛型**:提供类型安全的容器,避免运行时ClassCastException。 - **自动装箱与拆箱**:自动将基本类型转换为包装类或反之。 #### 五、输入输出(IO) - **FileInputStream/FileOutputStream**:用于文件读写。...

    java拦截器_类型转换_国际化

    - @AspectJ注解:Spring也支持基于注解的AOP,可以通过@Aspect注解定义切面,并使用@Before、@After等来定义拦截规则。 2. **类型转换**: - 自动类型转换:例如,int到long、byte到int等都是安全的转换,因为...

    Java高级课题.zip

    9. **Spring框架**:Java企业级开发中常用的IoC(控制反转)和AOP(面向切面编程)框架,包括依赖注入、Spring Boot、Spring MVC、Spring Data JPA等。 10. **JDBC与数据库交互**:数据库连接、事务处理、预编译SQL...

    375Spring15Team1

    Spring是一个全面的企业级应用开发框架,提供依赖注入、AOP(面向切面编程)、MVC(模型-视图-控制器)等特性,极大地简化了Java EE应用的开发。 13. **Maven**:作为Java项目的构建工具,Maven管理项目的构建、...

    JAVA学习路线图+就业面试宝典+android视频地址

    另外,Spring框架是企业级应用的首选,它的依赖注入和AOP(面向切面编程)能简化开发。 "就业面试宝典"则会提供各种面试题和解答,包括但不限于Java基础、数据结构与算法、操作系统原理、计算机网络知识,以及项目...

    《Java面试手册》.pdf

    - Spring是一个全面的企业级应用开发框架,提供了依赖注入(DI)和面向切面编程(AOP)等功能,简化了Java EE应用的开发。 9. MySQL数据库 - MySQL是一个广泛使用的开源关系型数据库,具有高性能、易用性和跨平台...

    JAVA高频笔试题_csdn_sty945.pdf

    在Spring AOP中,around通知是最强大的通知类型,可以在方法执行前后自定义行为,并且可以改变方法的执行结果。 2. JSP生命周期相关知识,包括JSP页面被用户请求时的生命周期方法调用顺序,即jspInit()只会在JSP...

    笔记笔记笔记

    Spring框架的理解与使用 - **Spring框架**:Spring是一个开源的轻量级Java开发框架,被广泛应用于企业级应用开发之中。它主要提供了依赖注入(Dependency Injection, DI)、面向切面编程(Aspect-Oriented ...

    java加强课程测试代码 反射、 代理 、泛型、beanUtils等

    这样可以防止在运行时出现ClassCastException,并在编译时捕获类型错误。泛型还有助于减少强制类型转换,提高代码复用。 4. BeanUtils: Apache Commons BeanUtils是Apache软件基金会的一个项目,提供了一系列工具...

    java从基础到应用编程经验

    - **泛型(Generics)**:允许在编译时检查类型安全,并避免运行时的ClassCastException。 - **枚举(Enum)**:提供了一种定义固定常量集的方式。 - **注解(Annotation)**:为元数据提供了一种标准化的标记方式,可用于...

    Java学习材料(499篇文章)

    11. **Spring框架**:作为Java企业级应用最常用的框架之一,Spring提供了依赖注入、AOP(面向切面编程)、MVC(模型-视图-控制器)等特性,简化了Java应用的开发。 12. **数据库连接**:Java JDBC(Java Database ...

Global site tag (gtag.js) - Google Analytics