在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();}}

您可能会注意到, CollaboratorService都没有接口,但是它们都不是代理候选者。 因此,此代码将在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的代理类相关推荐

  1. JDK和cglib生成代理类

    关于动态代理和静态代理 当一个对象(客户端)不能或者不想直接引用另一个对象(目标对象),这时可以应用代理模式在这两者之间构建一个桥梁–代理对象. 按照代理对象的创建时期不同,可以分为两种: 静态代理: ...

  2. c++ 虚函数_到底什么情况下会合成默认构造函数?

    来源:https://www.cnblogs.com/QG-whz/p/4676481.html 作者:good luck 编辑:公众号[编程珠玑] 编辑注:没有构造函数的时候编译器一定会生成默认构造 ...

  3. C++编译器何时为用户提供默认构造函数

    第一种是类成员中有成员是类对象,并且该成员的类含有默认构造函数,那么C++编译器会帮你给这个类也生成一个默认构造函数,用来调用其成员对象的构造函数,完成该成员的初始化构造.需要强调的是,如果这个成员的 ...

  4. [转]默认构造函数的作用

    构造函数主要用来初始化对象.它又分为静态(static)和实例(instance)构造函数两种类别.大家应该都了解如果来写类的构造函数,这里只说下默认构造函数的作用,以及在类中保留默认构造函数的重要性 ...

  5. 默认构造函数的作用(“A”方法没有采用“0”个参数的重载

    构造函数主要用来初始化对象.它又分为静态(static)和实例(instance)构造函数两种类别.大家应该都了解如何来写类的构造函数,这里只说下默认构造函数的作用,以及在类中保留默认构造函数的重要性 ...

  6. C++ 合成默认构造函数的真相

    http://www.cnblogs.com/QG-whz/p/4676481.html 对于C++默认构造函数,我曾经有两点误解: 类如果没有定义任何的构造函数,那么编译器(一定会!)将为类定义一个 ...

  7. 代理详解 静态代理+JDK/CGLIB 动态代理实战

    1. 代理模式 代理模式是一种比较好理解的设计模式.简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对 ...

  8. cglib动态代理jar包_代理模式详解:静态代理+JDK/CGLIB 动态代理实战

    1. 代理模式 代理模式是一种比较好的理解的设计模式.简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标 ...

  9. Java 结合实例学会使用 静态代理、JDK动态代理、CGLIB动态代理

    前言 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 很多人至今都是看到 代理就懵, 静态代理.动态代理.JDK动态代理.CGL ...

最新文章

  1. leetcode算法题--两个字符串的最小ASCII删除和★
  2. Android Annotation注解详解
  3. SAP Fiori Elements的change and save实现原理
  4. python扫雷游戏课程设计小组任务计划与分配表_Python开源扫雷游戏由网瘾少年制作,转手后月入18K,附赠所有源文件...
  5. 4怎样判断动作是否执行_汽车驾驶怎样试验高压火,怎样判断分电器盖是否破裂,来看看吧!...
  6. 红豆、绿豆、黑豆、花生、莲子、薏仁米放在一起吃,可以吗?
  7. 大学计算机vfp最新考试题库,大学计算机vfp考试选择题题库.doc
  8. python flask接收图像
  9. void和void指针解析
  10. 求n个连续自然数之和为一个非负整数的数组
  11. 简单易行的番茄时间管理法——学会专注(转载)
  12. java list 冒泡排序_冒泡排序详细分析JAVA
  13. 阿里巴巴开发手册介绍
  14. 大专计算机专业学期计划,大专三年学习目标计划
  15. 做一个文字跟随鼠标java_JavaScript实现文字跟随鼠标特效
  16. web邮箱和客户端的区别
  17. mysql oob_mysql 读写文件特性和OOB注入
  18. 75款响应式国外漂亮网站建设中模板(上线倒计时模板)
  19. css图形动画,CSS3 实现图形下落动画效果
  20. EtherCAT主站SOEM源码解析----ecx_siiPDO()

热门文章

  1. 2015蓝桥杯省赛---java---B---3(三羊献瑞)
  2. java代码识别_识别Java中的代码气味
  3. jboss eap 7_使用JBoss EAP 7的HTTP / 2
  4. 设计模式适配器模式_21世纪的设计模式:适配器模式
  5. java状态模式和策略模式_Java状态和策略设计模式之间的差异
  6. java aspectj_Java:AspectJ的异常翻译
  7. guava和commons_使用Guava CharMatcher和Apache Commons Lang StringUtils确定字符串中字符或整数的存在...
  8. 使用Spring Rest和Spring Data JPA和H2以及Spring Boot示例的Restful API
  9. 创建一个坚固的备份系统
  10. Java命令行界面(第28部分):getopt4j