当前位置: 首页 > news >正文

Spring的Bean原型模式下的使用

目录

1、问题原因

1.1、注入点只初始化一次

1.2、代理模式问题

1.3、使用不当的获取方式

2、解决方案

2.1. ApplicationContext获取

2.2. 使用ObjectProvider

2.3. 使用Lookup方法

2.4. 使用Provider接口

3、原型模式的应用场景

1. 有状态的Bean

2. 线程不安全的对象

3. 需要每次使用新实例的场景

4. 需要避免副作用的场景

4、注意事项


前言

        原型(Prototype)模式的Bean在Spring中每次请求时都会创建一个新的实例,这与单例(Singleton)模式形成对比。

如下图所示:

        默认情况下,Spring中的Bean采用单例模式,即容器始终返回同一实例。然而,通过将singleton属性设置为false,可以使得每次请求都返回一个新的Bean实例。

        当你在Spring中使用原型(prototype)作用域的Bean时,如果通过@Autowired注入后发现仍然是单例行为。


1、问题原因

1.1、注入点只初始化一次

@Autowired在依赖注入时只发生一次(在Bean创建时),之后每次访问都是同一个实例。

1.2、代理模式问题

        如果原型Bean被代理(如AOP代理),而代理配置不正确,可能导致每次获取的都是同一个代理实例。

1.3、使用不当的获取方式

直接通过@Autowired注入原型Bean实际上违背了原型模式的设计初衷

总结:

  @Autowired在依赖注入时只执行一次,将原型Bean注入到单例Bean中时,这个注入动作只发生一次,因此单例Bean持有的始终是同一个原型Bean实例。这与原型Bean的设计初衷相违背。

        正确的方式应该是每次需要新实例时都从容器中显式获取,而不是在初始化时就注入并持有。


2、解决方案

2.1. ApplicationContext获取

@Autowired
private ApplicationContext applicationContext;public void someMethod() {PrototypeBean bean = applicationContext.getBean(PrototypeBean.class);// 每次调用getBean()都会返回新实例
}

2.2. 使用ObjectProvider

使用(Spring 4.3+)版本,代码示例如下:

@Autowired
private ObjectProvider<PrototypeBean> prototypeBeanProvider;public void someMethod() {PrototypeBean bean = prototypeBeanProvider.getObject();// 每次getObject()都会返回新实例
}

2.3. 使用Lookup方法

通过@lookup注解,重写get${method}方法。

代码示例如下:

@Configuration
public class AppConfig {@Bean@Scope("prototype")public PrototypeBean prototypeBean() {return new PrototypeBean();}
}@Component
public class SingletonBean {// 使用方法注入@Lookuppublic PrototypeBean getPrototypeBean() {return null; // Spring会覆盖此方法实现}public void someMethod() {PrototypeBean bean = getPrototypeBean(); // 每次调用都返回新实例}
}

2.4. 使用Provider接口

Provider接口是位于(javax.inject)包下。

代码实现如下:

@Autowired
private Provider<PrototypeBean> prototypeBeanProvider;public void someMethod() {PrototypeBean bean = prototypeBeanProvider.get();// 每次get()都会返回新实例
}

3、原型模式的应用场景

1. 有状态的Bean

当Bean需要维护状态,且不同使用者需要独立的状态时:

  • 用户会话相关的对象

  • 请求处理过程中的上下文对象

  • 购物车实例

  • 表单数据对象

@Scope("prototype")
@Component
public class ShoppingCart {private List<Item> items = new ArrayList<>();// 每个用户需要自己的购物车实例
}

2. 线程不安全的对象

当Bean不是线程安全的,且需要在多线程环境中使用时:

  • 简单的日期格式化器(SimpleDateFormat)

  • 随机数生成器

  • 某些第三方库的非线程安全类

@Scope("prototype")
@Component
public class DateFormatter {private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");// 每个线程需要自己的实例
}

3. 需要每次使用新实例的场景

  • 临时计算器对象

  • 事务处理器(某些场景下)

  • 原型设计模式的实际应用

@Scope("prototype")
@Component
public class ReportGenerator {// 每次生成报告都需要新的实例来保持独立性
}

4. 需要避免副作用的场景

当Bean的操作会修改内部状态,且这种修改不应该影响其他使用者时:

  • 数据处理器

  • 文件处理器

  • 临时缓存对象

@Scope("prototype")
@Component
public class FileProcessor {private File currentFile;// 每个文件处理需要独立的处理器实例
}

4、注意事项

  1. 内存考虑:原型Bean不会自动销毁,需要确保不会造成内存泄漏

  2. 性能影响:频繁创建复杂对象可能影响性能

  3. 依赖管理:原型Bean注入单例Bean时要特别小心(通常使用方法注入)

  4. 测试复杂性:原型Bean可能增加测试的复杂性

        正确使用原型模式可以解决许多与状态和线程安全相关的问题,但需要权衡其带来的资源开销。

http://www.xdnf.cn/news/1085689.html

相关文章:

  • Java创建型模式---原型模式
  • 【C语言】指针与回调机制学习笔记
  • 【Java安全】反射基础
  • RoboRefer:面向机器人视觉-语言模型推理的空间参考
  • Web后端开发-分层解耦
  • Playfun即将开启大型Web3线上活动,打造沉浸式GameFi体验生态
  • 【ElasticSearch实用篇-01】需求分析和数据制造
  • turborepo 如何解决git管理包过大的问题
  • 病虫害数据集
  • 「Windows/Mac OS」AIGC图片生成视频 ,webui + stable-diffusion环境部署教程
  • AI编程才刚起步,对成熟的软件工程师并未带来质变
  • 【学习笔记】大数定理,频率与概率,均值与期望的区别
  • 深入解析TCP:可靠传输的核心机制与实现逻辑(三次握手、四次挥手、流量控制、滑动窗口、拥塞控制、慢启动、延时应答、面向字节流、粘包问题)
  • Java 命令行参数详解:系统属性、JVM 选项与应用配置
  • PCA通过“找最大方差方向”实现降维,本质是用更少的变量捕捉原始数据的主要模式
  • 3S技术+ArcGIS/ENVI全流程实战:水文、气象、灾害、生态、环境及卫生等领域应用
  • 深度学习7(梯度下降算法改进)
  • 使用Ideal创建一个spring boot的helloWorld项目
  • TMC4361A 使用(未验证)
  • 如何排查服务器中已经存在的后门程序?
  • 【应急响应】Linux 自用应急响应工具(LinuxCheckShoot)
  • 接口漏洞怎么抓?Fiddler 中文版 + Postman + Wireshark 实战指南
  • 提示工程(Prompt Engineering)研究进展
  • Camera相机人脸识别系列专题分析之十六:人脸特征检测FFD算法之libcvface_api.so数据结构详细注释解析
  • AWS VPC Peering
  • Linux中程序的limits中的Max open files的配置由哪些参数决定
  • 明星AI自动化测试工具Midscene.js源码解析
  • Pr插件图文安装教程
  • 实用机器学习
  • C盘瘦身 -- 虚拟内存文件 pagefile.sys