首页 > 编程语言 >Spring Bean多例作用域:原型模式的深度剖析与源码之旅

Spring Bean多例作用域:原型模式的深度剖析与源码之旅

时间:2024-06-01 11:30:37浏览次数:30  
标签:... 实例 多例 作用域 Spring Bean 源码 Scope

1. 引言

在Spring框架中,Bean的多例作用域(prototype)提供了一种重要的实例化模式,它允许每次从Spring容器中请求Bean时都创建一个新的实例。这种模式在处理需要频繁创建和销毁实例的场景,以及不希望在不同请求或会话之间共享状态的Bean时特别有用。本文将通过深度剖析多例作用域的原理,并结合实战案例,展示其在实际开发中的应用。


2. 多例(Prototype)作用域概述

多例作用域是Spring Bean的一种非默认作用域,表示每次从Spring容器中请求Bean时,都会创建一个新的Bean实例。这种作用域适用于需要频繁创建和销毁实例的Bean,以及不希望在不同请求或会话之间共享状态的Bean。


3. 多例作用域的特性

  1. 非单例性:与单例(singleton)作用域不同,多例作用域中的Bean是非单例的,即每次从容器中获取Bean时都会创建一个新的实例。
  2. 状态独立性:由于每次请求都会生成新的Bean实例,因此多例作用域中的Bean具有状态独立性,不会受到其他请求或会话的影响。
  3. 性能考虑:虽然多例作用域提供了状态独立性和灵活性,但由于需要频繁创建和销毁Bean实例,因此在使用时需要考虑性能问题。对于需要大量实例的场景,可以通过合理的缓存和池化策略来优化性能。

4. 多例作用域的用法

  1. XML配置:在XML配置文件中,可以通过<bean>标签的scope属性设置为prototype来指定Bean的作用域为多例。
<bean id="person" class="org.example.Person" scope="prototype" />
  1. 注解配置:在注解配置中,可以使用@Scope注解来指定Bean的作用域为多例。
@Component  
@Scope("prototype")  
public class Person {  
    // ...  
}

5. 实战案例

案例一:DTO(数据传输对象)的创建

在Web应用中,DTO常用于在层与层之间传递数据。由于DTO通常只用于单次请求,且不希望被其他请求或会话共享,因此非常适合使用多例作用域。

@Component  
@Scope("prototype")  
public class UserDTO {  
    private String username;  
    private String email;  
    // getters and setters...  
}  
  
// 在服务层中,每次需要传递用户数据时,都可以从容器中获取一个新的UserDTO实例  
@Service  
public class UserService {  
    @Autowired  
    private ApplicationContext applicationContext;  
  
    public UserDTO getUserData() {  
        UserDTO userDTO = applicationContext.getBean(UserDTO.class);  
        // populate userDTO with data...  
        return userDTO;  
    }  
}

案例二:线程安全的Bean

在多线程环境下,如果Bean的状态被多个线程共享,可能会导致数据不一致的问题。通过使用多例作用域,可以为每个线程创建一个独立的Bean实例,从而实现线程安全。

@Component  
@Scope("prototype")  
public class ThreadSafeBean {  
    // state variables...  
  
    public void executeTask() {  
        // task execution logic that requires thread safety...  
    }  
}  
  
// 在线程池或并发处理中,可以为每个任务注入一个新的ThreadSafeBean实例  
@Service  
public class TaskExecutor {  
    @Autowired  
    private ApplicationContext applicationContext;  
  
    public void executeTasks() {  
        ExecutorService executorService = Executors.newFixedThreadPool(10);  
        for (int i = 0; i < 100; i++) {  
            final int taskId = i;  
            executorService.submit(() -> {  
                ThreadSafeBean threadSafeBean = applicationContext.getBean(ThreadSafeBean.class);  
                threadSafeBean.executeTask();  
                // ...  
            });  
        }  
        executorService.shutdown();  
    }  
}

6. 源码分析

  1. Scope接口
    • Scope接口定义了作用域的基本行为,包括获取对象、移除对象等操作。
public interface Scope {  
    Object get(String name, ObjectFactory<?> objectFactory);  
    Object remove(String name);  
    // ...其他方法  
}
  1. PrototypeScope类
    • PrototypeScope类实现了Scope接口,用于处理多例作用域的逻辑。其核心方法是get,负责在每次请求时创建一个新的Bean实例。
public class PrototypeScope implements Scope, Serializable {  
    // ...省略其他方法  
  
    @Override  
    public Object get(String name, ObjectFactory<?> objectFactory) {  
        return objectFactory.getObject(); // 直接调用ObjectFactory的getObject方法创建新实例  
    }  
  
    // ...其他方法实现  
}
  1. AbstractBeanFactory中的doGetBean方法
    • AbstractBeanFactory是Spring框架中Bean工厂的核心实现类之一,其doGetBean方法负责Bean的创建和获取。对于多例作用域的Bean,会调用PrototypeScope的get方法。
protected <T> T doGetBean(  
        final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly)  
        throws BeansException {  
    // ...省略其他代码  
  
    // 判断是否是多例作用域  
    if (mbd.isPrototype()) {  
        // 对于多例Bean,不缓存,直接创建新实例  
        Object prototypeInstance = null;  
        try {  
            // 调用Scope的get方法,即PrototypeScope的get方法  
            prototypeInstance = ((Scope) this.scopes.get(scopeName)).get(beanName, () -> {  
                return createBean(beanName, mbd, args);  
            });  
        }  
        // ...省略异常处理和返回结果代码  
    }  
  
    // ...省略其他代码  
}
  1. 自定义作用域
    • 除了Spring内置的作用域外,我们还可以自定义作用域。自定义作用域需要实现Scope接口,并在Spring配置中注册。

7. 总结

多例作用域在Spring框架中提供了一种重要的实例化模式,允许根据需求为每个请求或任务创建独立的Bean实例。通过实战案例和源码的展示,可以看到多例作用域在处理DTO、线程安全Bean等场景时的实用性。同时,也需要注意到多例作用域可能带来的性能问题,并通过合理的缓存和池化策略来优化性能。作为高级Java工程师,应该深入理解多例作用域的原理和用法,以便在实际开发中能够灵活应用。


标签:...,实例,多例,作用域,Spring,Bean,源码,Scope
From: https://blog.csdn.net/m0_51176516/article/details/139287835

相关文章

  • WEB网页设计期末作业个人主页——简单的学生网页作业源码 基于HTML CSS制作个人简介网
    @TOC>......
  • PCL欧式距离聚类源码解析
    1.Findapointp10inspace,thereiskdTreeFindthenpointsclosesttohim,andjudgethedistancefromthesenpointstop.Putpointsp12,p13,p14….withdistanceslessthanthethresholdrinclassQFindabitofp12inQ(p10)andrepeat1.3Fi......
  • Spring Boot集成sse实现chatgpt流式交互
    1.什么是sse?SSE(Server-SentEvents)是一种允许服务器向客户端推送实时数据的技术,它建立在HTTP和简单文本格式之上,提供了一种轻量级的服务器推送方式,通常也被称为“事件流”(EventStream)。他通过在客户端和服务端之间建立一个长连接,并通过这条连接实现服务端和客户端的消息实......
  • 基于springboot的毕业设计成绩管理系统源码数据库
    基于springboot的毕业设计成绩管理系统源码数据库传统办法管理信息首先需要花费的时间比较多,其次数据出错率比较高,而且对错误的数据进行更改也比较困难,最后,检索数据费事费力。因此,在计算机上安装毕业设计成绩管理系统软件来发挥其高效地信息处理的作用,可以规范信息管理流程,让......
  • 进件最新版点微同城源码34.7+全套插件+小程序前后端
    模板挺好看的带全套插件自己耐心点配置一下插件可以H5可以小程序资源链接:最新版点微同城源码34.7+全套插件+小程序前后端-资源吧......
  • Springboot 开发 -- 跨域问题技术详解
    一、跨域的概念跨域访问问题指的是在客户端浏览器中,由于安全策略的限制,不允许从一个源(域名、协议、端口)直接访问另一个源的资源。当浏览器发起一个跨域请求时,会被浏览器拦截,并阻止数据的传输。这种限制是为了保护用户的隐私和安全,防止恶意网站利用用户的浏览器向其他网站......
  • springboot 获取静态资源文件夹
    @ComponentpublicclassStaticResourcePathResolver{privatefinalServletContextservletContext;@AutowiredpublicStaticResourcePathResolver(ServletContextservletContext){this.servletContext=servletContext;}publicS......
  • Springboot计算机毕业设计亚洲杯志愿者管理系统小程序【附源码】开题+论文+mysql+程序
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景:随着各类大型活动的增多,志愿者管理成为了一个日益重要的问题。特别是在亚洲杯这样的国际性赛事中,高效的志愿者管理系统对于保障活动的顺利进行至关重......
  • Springboot计算机毕业设计牙科预约微信小程序【附源码】开题+论文+mysql+程序+部署
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景:随着移动互联网的普及和微信平台的广泛应用,微信小程序已成为连接线上线下的重要桥梁。在医疗健康领域,传统的牙科预约方式往往存在着效率低下、操作繁......
  • 1v1视频软件源码,通过jsonp跨域的代码分析
    1v1视频软件源码,通过jsonp跨域的代码分析通常为了减轻1v1视频软件源码web服务器的负载,我们把js、css,img等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实......