遇到什么问题

假设单例 BeanA 需要使用原型 BeanB(BeanB 可能是 BeanA 的一个属性值)。可是容器仅创建一次单例 BeanA,因此只有一次机会来设置属性 BeanB。

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)@Servicepublic class OrderService {}@Servicepublic class UserService {@Autowiredprivate OrderService orderService;public OrderService getOrderService() {return orderService;}}@Configuration@ComponentScanpublic class Main {public static void main(String[] args) {AnnotationConfigApplicationContext context =new AnnotationConfigApplicationContext(Main.class);UserService userService = context.getBean(UserService.class);OrderService orderService = userService.getOrderService();OrderService orderService1 = userService.getOrderService();//tureSystem.out.println(orderService == orderService1);}}

如果直接使用@Autowired注入,容器仅创建一次单例UserService,因此只有一次机会来设置OrderService。

那么,如何在单例 Bean 中注入原型 Bean 呢?

解决方案 1:实现 ApplicationContextAware

第一种解决方案,可以让UserService实现ApplicationContextAware接口,然后在每次需要使用原型 BeanOrderService时通过调用容器的getBean方法。

@Servicepublic class UserService implements ApplicationContextAware {private ApplicationContext context;public OrderService getOrderService() {return context.getBean(OrderService.class);}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {context = applicationContext;}}

Spring 官方并不建议使用这种方式:

The preceding is not desirable, because the business code is aware of and coupled to the Spring Framework. Method Injection, a somewhat advanced feature of the Spring IoC container, lets you handle this use case cleanly.

前面的内容是不理想的,因为业务代码知道并耦合到 Spring 框架。 方法注入是 Spring IoC 容器的一项高级功能,使您可以干净地处理此用例。

解决方案 2:使用@Lookup,实现方法注入

@Lookup

先来看一下@Lookup源码

@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Lookup {/** * This annotation attribute may suggest a target bean name to look up. * If not specified, the target bean will be resolved based on the * annotated method's return type declaration. */String value() default "";}

@Lookup默认是通过方法的返回类型声明来解析目标 Bean,也可以通过 value 来指定需要查找的目标 BeanName

介绍

https://docs.spring.io/spring/docs/5.1.9.RELEASE/spring-framework-reference/core.html#beans-factory-lookup-method-injection

Lookup method injection is the ability of the container to override methods on container-managed beans and return the lookup result for another named bean in the container. The lookup typically involves a prototype bean, as in the scenario described in the preceding section. The Spring Framework implements this method injection by using bytecode generation from the CGLIB library to dynamically generate a subclass that overrides the method.

机器翻译:查找方法注入是容器覆盖容器管理的 Bean 上的方法并返回容器中另一个命名 Bean 的查找结果的能力。 查找通常涉及原型 bean,如上一节中所述。 Spring 框架通过使用从 CGLIB 库生成字节码来动态生成覆盖该方法的子类来实现此方法注入。

使用限制

For this dynamic subclassing to work, the class that the Spring bean container subclasses cannot be final, and the method to be overridden cannot be final, either.

为了使此动态子类起作用,Spring Bean 容器子类的类也不能是 final,而要覆盖的方法也不能是 final。

Unit-testing a class that has an abstract method requires you to subclass the class yourself and to supply a stub implementation of the abstract method.

对具有抽象方法的类进行单元测试需要您自己对该类进行子类化,并提供该抽象方法的存根实现。

A further key limitation is that lookup methods do not work with factory methods and in particular not with @Bean methods in configuration classes, since, in that case, the container is not in charge of creating the instance and therefore cannot create a runtime-generated subclass on the fly.

另一个关键限制是,查找方法不适用于工厂方法,尤其不适用于配置类中的@Bean 方法,因为在这种情况下,容器不负责创建实例,因此无法创建运行时生成的子类。

根据 Spring 官方文档,我们可以知道:

  1. 方法注入是通过 CGLIB 生成字节码来动态生成覆盖该方法的子类来实现此方法注入
  2. 因为是用 CGLIB 来实现的,所以当前类和当前方法是不能为 final 的
  3. Spring 中使用@Lookup来实现方法注入

使用@Lookup 实现单例 Bean 中注入原型 Bean

@Servicepublic abstract class UserService {@Lookuppublic abstract OrderService getOrderServiceUsingLookup();}

虽然这个类是抽象的,但是还可以被实例化到 Spring 容器中,因为 Spring 会对当前类生成子类来实现方法注入。至于具体是怎么生成的增强对象,读者可以自行 debug 源码学习。

UserService代理对象

单元测试 applicationinfomanager bean无法注入_你真的会用Spring吗?如何在单例Bean中注入原型Bean...相关推荐

  1. Spring(07)——单例注入多例之lookup-method

    2019独角兽企业重金招聘Python工程师标准>>> Spring(07)--单例注入多例之lookup-method 博客分类: spring 7 单例注入多例之lookup-m ...

  2. 自动注入、加载 properties 文件、scope 属性、单例设计模式

    一.自动注入 在 Spring 配置文件中对象名和 ref="id"id 名相同使用自动注入,可以不配置<property/> 两种配置办法 2.1 在<bean ...

  3. Struts+Spring+Hibernate处理Lob(Blob,Clob)--sessionFactory中注入 org.springframework.jdbc.support.lob.Def

    [转载]org.springframework.jdbc.support.lob. 转载▼ 标签: 转载 分类: spring 原文地址:org.springframework.jdbc.suppor ...

  4. spring容器bean的作用域 spring容器是否是单例的一些问题

    Spring容器中Bean的作用域 当通过Spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域.Spring支持如下5种作用域: singleto ...

  5. spring boot整合Quartz 在Job类中注入其他对象报空指针异常java.lang.NullPointerException at com.sxt.quartz.QuartzDemo.e

    情况在Job 类中注入RedisTemplate 报空指针异常 原因:我们使用JobDetailFactoryBean 帮我们创建对象 实际上调用的是AdaptableJobFactory 下的这个方 ...

  6. spring学习(48):自动装配中定义的bean的作用域

    目录结构 pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns=&quo ...

  7. Unity学习_我终于终于把unity音乐这块用单例控制得死死的了(1)!!!!

    两个脚本 AudioManager.cs(绑定在播放音乐的组件上,作用是不让其销毁,并且在场景切换一个循环回到初始场景是判断重复) using System.Collections; using Sy ...

  8. controller如何保证当前只有一个线程执行_今天我们来聊一聊 Spring 中的线程安全性...

    优质文章,及时送达 Spring与线程安全 Spring作为一个IOC/DI容器,帮助我们管理了许许多多的"bean".但其实,Spring并没有保证这些对象的线程安全,需要由开发 ...

  9. factorybean 代理类不能按照类型注入_彻底搞懂依赖注入(一)Bean实例创建过程

    点击上方"Java知音",选择"置顶公众号" 技术文章第一时间送达! 上一章介绍了Bean的加载过程(IOC初始化过程),加载完成后,紧接着就要用到它的依赖注入 ...

最新文章

  1. POJ - 1661 Help Jimmy DP
  2. ValueError: need at most 63 handles, got a sequence of length 65
  3. stm32l0的停止模式怎么唤醒_汇聚力量,守护安全:2020 “AnQ唤醒云课堂”圆满收官!...
  4. SVN中提交时提示副本被锁定,执行清理时也提示副本被锁定的解决办法
  5. 利用Spring的ApplicationEvent执行自定义方法
  6. NAT概念解释(不完全版,但不会搞错...)
  7. 【OpenCV3】图像的读取、显示与保存
  8. UML学习-活动图创建
  9. sql server2008r2 没有提示_SQL学习之旅(1)
  10. /proc/sys/vm虚拟内存参数
  11. Linux 下配置 Hadoop2.x 高可用 zookeeper Yarn,详细步骤。
  12. 对付镜像网站非常有效的办法
  13. rstudio server docker 部署_Docker环境运行Spring Cloud项目
  14. python基础快速入门day01
  15. WebLogic部署项目成功后,访问Error 404
  16. python 柱状图和折线图放在一起_一款多条折线与柱状图共存图表
  17. 微信小程序的数据库用mysql可以_微信小程序之在前端使用数据库
  18. Android studio连接网易MuMu模拟器
  19. iphone捷径未能连接服务器,ios13无法安装第三方捷径怎么办 不允许不受信任的快捷指令解决方法...
  20. 软件设计师 如何准备考试(转载)

热门文章

  1. 表之顺序结构和链式结构
  2. MySQL读写分离中间件解决
  3. mysql count if语句_COUNT分组条件去重的sql统计语句示例(mysql)
  4. 推荐一款Java开发的精美个人博客
  5. 不好意思,我真的不知道MySQL的窗口函数...
  6. 算法--三种方法求连续子数组的最大和
  7. 04-JDBC学习手册:JDBC中使用transaction(事务)编程和Javabean定义
  8. 爬取虎牙之二:试用htmlunit模拟js爬取ajax页面
  9. Linux的编译器vi之最详细介绍
  10. Spring Cloud(五) Zuul Filter