Spring4:没有默认构造函数的基于CGLIB的代理类
在Spring中,如果要代理的目标对象的类未实现任何接口,则将创建基于CGLIB的代理。 在Spring 4之前,基于CGLIB的代理类需要默认的构造函数。 这不是CGLIB库的限制,而是Spring本身。 幸运的是,从Spring 4开始,这不再是问题。 基于CGLIB的代理类不再需要默认的构造函数。 这如何影响您的代码? 让我们来看看。
依赖注入的惯用法之一是构造函数注入。 它通常在需要注入的依赖项时使用,并且在启动对象后不得更改。 在本文中,我不会讨论为什么和何时应该使用构造函数依赖项注入。 我假设您在代码中使用了这个习惯用法,或者您考虑使用它。 如果您有兴趣了解更多信息,请参见本文底部的资源部分。
不含豆的施工剂注射
具有以下协作者:
package pl.codeleak.services;import org.springframework.stereotype.Service;@Service
public class Collaborator {public String collaborate() {return "Collaborating";}
}
我们可以通过构造函数轻松注入它:
package pl.codeleak.services;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class SomeService {private final Collaborator collaborator;@Autowiredpublic SomeService(Collaborator collaborator) {this.collaborator = collaborator;}public String businessMethod() {return collaborator.collaborate();}}
您可能会注意到, Collaborator
和Service
都没有接口,但是它们都不是代理候选者。 因此,此代码将在Spring 3和Spring 4上正常运行:
package pl.codeleak.services;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import pl.codeleak.Configuration;import static org.assertj.core.api.Assertions.assertThat;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Configuration.class)
public class WiringTests {@Autowiredprivate SomeService someService;@Autowiredprivate Collaborator collaborator;@Testpublic void hasValidDependencies() {assertThat(someService).isNotNull().isExactlyInstanceOf(SomeService.class);assertThat(collaborator).isNotNull().isExactlyInstanceOf(Collaborator.class);assertThat(someService.businessMethod()).isEqualTo("Collaborating");}
}
代豆施工剂注射
在许多情况下,您的bean需要在运行时用AOP proxy
进行修饰,例如,当您想将声明性事务与@Transactional
注释一起使用时。 为了可视化,我创建了一个方面,将为SomeService
所有方法提供建议。 在定义了以下方面之后, SomeService
将成为代理的候选者:
package pl.codeleak.aspects;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;@Aspect
@Component
public class DummyAspect {@Before("within(pl.codeleak.services.SomeService)")public void before() {// do nothing}}
当我使用Spring 3.2.9重新运行测试时,出现以下异常:
Could not generate CGLIB subclass of class [class pl.codeleak.services.SomeService]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
可以通过为SomeService
提供默认的,无参数的构造函数来简单地解决此问题,但这不是我想要做的-因为我还需要使依赖关系成为非最终的。
另一个解决方案是为SomeService
提供接口。 但是,在很多情况下,您不需要创建接口。
更新到Spring 4可以立即解决该问题。 如文档所述:
基于CGLIB的代理类不再需要默认的构造函数。 通过objenesis库提供支持,该库以内联方式重新打包并作为Spring框架的一部分分发。 通过这种策略,不再为代理实例调用任何构造函数。
我创建的测试将失败,但可以看到为SomeService
创建了CGLIB代理:
java.lang.AssertionError:
Expecting:<pl.codeleak.services.SomeService@6a84a97d>
to be exactly an instance of:<pl.codeleak.services.SomeService>
but was an instance of:<pl.codeleak.services.SomeService$$EnhancerBySpringCGLIB$$55c3343b>
从测试中删除第一个断言后,它将运行得非常好。
资源资源
- 如果您需要了解有关构造函数依赖注入的更多信息,请查看Petri Kainulainen撰写的这篇出色文章: http ://www.petrikainulainen.net/software-development/design/why-i-changed-my-mind-about 场注入 。
- Spring4中的核心容器改进: http : //docs.spring.io/spring/docs/current/spring-framework-reference/html/new-in-4.0.html#_core_container_improvements
- 您可能也有兴趣阅读有关Spring的其他文章: Spring 4:带有Java 8 Date-Time API的@DateTimeFormat和
在Spring MVC应用程序中使用Bean Validation 1.1获得更好的错误消息
翻译自: https://www.javacodegeeks.com/2014/07/spring-4-cglib-based-proxy-classes-with-no-default-constructor.html
Spring4:没有默认构造函数的基于CGLIB的代理类相关推荐
- JDK和cglib生成代理类
关于动态代理和静态代理 当一个对象(客户端)不能或者不想直接引用另一个对象(目标对象),这时可以应用代理模式在这两者之间构建一个桥梁–代理对象. 按照代理对象的创建时期不同,可以分为两种: 静态代理: ...
- c++ 虚函数_到底什么情况下会合成默认构造函数?
来源:https://www.cnblogs.com/QG-whz/p/4676481.html 作者:good luck 编辑:公众号[编程珠玑] 编辑注:没有构造函数的时候编译器一定会生成默认构造 ...
- C++编译器何时为用户提供默认构造函数
第一种是类成员中有成员是类对象,并且该成员的类含有默认构造函数,那么C++编译器会帮你给这个类也生成一个默认构造函数,用来调用其成员对象的构造函数,完成该成员的初始化构造.需要强调的是,如果这个成员的 ...
- [转]默认构造函数的作用
构造函数主要用来初始化对象.它又分为静态(static)和实例(instance)构造函数两种类别.大家应该都了解如果来写类的构造函数,这里只说下默认构造函数的作用,以及在类中保留默认构造函数的重要性 ...
- 默认构造函数的作用(“A”方法没有采用“0”个参数的重载
构造函数主要用来初始化对象.它又分为静态(static)和实例(instance)构造函数两种类别.大家应该都了解如何来写类的构造函数,这里只说下默认构造函数的作用,以及在类中保留默认构造函数的重要性 ...
- C++ 合成默认构造函数的真相
http://www.cnblogs.com/QG-whz/p/4676481.html 对于C++默认构造函数,我曾经有两点误解: 类如果没有定义任何的构造函数,那么编译器(一定会!)将为类定义一个 ...
- 代理详解 静态代理+JDK/CGLIB 动态代理实战
1. 代理模式 代理模式是一种比较好理解的设计模式.简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对 ...
- cglib动态代理jar包_代理模式详解:静态代理+JDK/CGLIB 动态代理实战
1. 代理模式 代理模式是一种比较好的理解的设计模式.简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标 ...
- Java 结合实例学会使用 静态代理、JDK动态代理、CGLIB动态代理
前言 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 很多人至今都是看到 代理就懵, 静态代理.动态代理.JDK动态代理.CGL ...
最新文章
- leetcode算法题--两个字符串的最小ASCII删除和★
- Android Annotation注解详解
- SAP Fiori Elements的change and save实现原理
- python扫雷游戏课程设计小组任务计划与分配表_Python开源扫雷游戏由网瘾少年制作,转手后月入18K,附赠所有源文件...
- 4怎样判断动作是否执行_汽车驾驶怎样试验高压火,怎样判断分电器盖是否破裂,来看看吧!...
- 红豆、绿豆、黑豆、花生、莲子、薏仁米放在一起吃,可以吗?
- 大学计算机vfp最新考试题库,大学计算机vfp考试选择题题库.doc
- python flask接收图像
- void和void指针解析
- 求n个连续自然数之和为一个非负整数的数组
- 简单易行的番茄时间管理法——学会专注(转载)
- java list 冒泡排序_冒泡排序详细分析JAVA
- 阿里巴巴开发手册介绍
- 大专计算机专业学期计划,大专三年学习目标计划
- 做一个文字跟随鼠标java_JavaScript实现文字跟随鼠标特效
- web邮箱和客户端的区别
- mysql oob_mysql 读写文件特性和OOB注入
- 75款响应式国外漂亮网站建设中模板(上线倒计时模板)
- css图形动画,CSS3 实现图形下落动画效果
- EtherCAT主站SOEM源码解析----ecx_siiPDO()
热门文章
- 2015蓝桥杯省赛---java---B---3(三羊献瑞)
- java代码识别_识别Java中的代码气味
- jboss eap 7_使用JBoss EAP 7的HTTP / 2
- 设计模式适配器模式_21世纪的设计模式:适配器模式
- java状态模式和策略模式_Java状态和策略设计模式之间的差异
- java aspectj_Java:AspectJ的异常翻译
- guava和commons_使用Guava CharMatcher和Apache Commons Lang StringUtils确定字符串中字符或整数的存在...
- 使用Spring Rest和Spring Data JPA和H2以及Spring Boot示例的Restful API
- 创建一个坚固的备份系统
- Java命令行界面(第28部分):getopt4j