简识Spring创建Bean方式和设计模式

一、理论解释:

Spring在创建Bean时主要有四种方式,这些方式分别涉及到了不同的设计模式。以下是具体的创建方式及对应的设计模式:

  1. 通过反射调用构造方法创建Bean

    • 方式:在Spring的配置文件中,使用<bean>标签的class属性指定要创建的Bean的完整类名。Spring容器内部会自动调用该类型的无参构造方法(或带参数的构造方法,此时需要配合<constructor-arg>标签指定参数)来创建Bean对象,并将其放在容器中以供使用。
    • 设计模式:这种方式主要使用了简单工厂模式的思想,即通过一个工厂类(在这里是Spring容器)来创建对象,但不需要显式地编写工厂类代码。不过,严格来说,由于Spring容器本身是一个复杂的框架,其内部实现可能涉及到了更多的设计模式,但在此处我们主要关注其对外提供的创建Bean的方式。
  2. 通过静态工厂方法创建Bean

    • 方式:首先编写一个包含静态方法的工厂类,该方法返回要创建的Bean对象。然后在Spring的配置文件中,使用<bean>标签的class属性指定工厂类的完整类名,并使用factory-method属性指定静态工厂方法名。Spring容器会自动调用该静态方法来获取Bean对象。
    • 设计模式:这种方式明确使用了静态工厂模式。静态工厂模式是一种创建型设计模式,它通过一个包含静态方法的类来创建对象,而不需要将对象作为类的成员。
  3. 通过实例工厂方法创建Bean

    • 方式:首先编写一个普通的工厂类(非静态),该类包含一个返回要创建的Bean对象的方法。然后在Spring的配置文件中,先使用<bean>标签创建一个工厂类的实例(即工厂Bean),再使用另一个<bean>标签的factory-bean属性指定工厂Bean的ID,并使用factory-method属性指定工厂方法名。Spring容器会先创建工厂Bean实例,然后调用其方法来获取Bean对象。
    • 设计模式:这种方式使用了工厂方法模式。工厂方法模式是一种创建型设计模式,它通过一个工厂类的方法来创建对象,但工厂类本身是一个普通类(非静态类)。
  4. 通过FactoryBean创建Bean

    • 方式:编写一个实现FactoryBean接口的类,该接口包含三个方法:getObject()用于返回要创建的Bean对象,getObjectType()用于返回Bean对象的类型,isSingleton()用于指定Bean对象是否为单例。然后在Spring的配置文件中,使用<bean>标签的class属性指定FactoryBean实现类的完整类名。Spring容器会自动调用FactoryBeangetObject()方法来获取Bean对象。
    • 设计模式:这种方式虽然表面上看起来与普通的Bean创建方式类似,但实际上它利用了FactoryBean接口的特殊性质来实现了一种更灵活的Bean创建方式。这种方式可以看作是对工厂方法模式的一种扩展或变种,因为它允许在创建Bean对象时进行更多的自定义操作(如延迟加载、代理创建等)。不过,从更广泛的角度来看,它也可以被视为一种代理模式的应用,因为FactoryBean实际上是在为真正的Bean对象创建一个代理或包装器。

综上所述,Spring在创建Bean时主要使用了简单工厂模式(通过反射调用构造方法)、静态工厂模式、工厂方法模式和代理模式(通过FactoryBean)等设计模式。这些模式的应用使得Spring能够灵活地创建和管理Bean对象,从而满足了复杂应用程序的需求。

------分界线--------------------------------------------------------------------------------------------------------------

二、示例代码解释

当然,下面我将根据上面提到的几种创建Bean的方式和对应的设计模式,给出具体的示例代码,并简要说明每个示例以及需要注意的事项。

1. 通过反射调用构造方法创建Bean

示例代码

// 定义一个简单的Bean类
public class MyBean {private String name;// 无参构造方法public MyBean() {}// 带参数的构造方法(虽然在这个例子中未使用,但Spring支持)public MyBean(String name) {this.name = name;}// Getter和Setter方法public String getName() {return name;}public void setName(String name) {this.name = name;}
}// Spring配置文件(applicationContext.xml)
<bean id="myBean" class="com.example.MyBean"/>

说明

  • 在Spring配置文件中,通过<bean>标签的class属性指定了要创建的Bean类。
  • Spring容器会调用该类的无参构造方法来创建Bean实例。

注意事项

  • 确保Bean类有一个可访问的无参构造方法。
  • 如果需要注入依赖,可以使用<property><constructor-arg>标签。

2. 通过静态工厂方法创建Bean

示例代码

// 静态工厂类
public class MyBeanFactory {// 静态工厂方法public static MyBean createMyBean() {return new MyBean();}
}// Spring配置文件(applicationContext.xml)
<bean id="myBean" class="com.example.MyBeanFactory" factory-method="createMyBean"/>

说明

  • 在Spring配置文件中,通过<bean>标签的class属性指定了工厂类,并通过factory-method属性指定了静态工厂方法。
  • Spring容器会调用该静态方法来创建Bean实例。

注意事项

  • 确保工厂方法是静态的。
  • 工厂方法返回的对象类型应与配置文件中声明的Bean类型一致。

3. 通过实例工厂方法创建Bean

示例代码

// 实例工厂类
public class MyInstanceFactory {// 实例工厂方法public MyBean createMyBean() {return new MyBean();}
}// Spring配置文件(applicationContext.xml)
<!-- 首先创建工厂Bean实例 -->
<bean id="myInstanceFactory" class="com.example.MyInstanceFactory"/>
<!-- 然后通过工厂Bean实例创建目标Bean -->
<bean id="myBean" factory-bean="myInstanceFactory" factory-method="createMyBean"/>

说明

  • 在Spring配置文件中,首先通过<bean>标签创建了一个工厂Bean实例。
  • 然后通过另一个<bean>标签的factory-bean属性指定了工厂Bean的ID,并通过factory-method属性指定了工厂方法。
  • Spring容器会先创建工厂Bean实例,然后调用其方法来创建目标Bean实例。

注意事项

  • 确保工厂方法是实例方法(非静态)。
  • 工厂Bean实例和目标Bean实例的生命周期是独立的。

4. 通过FactoryBean创建Bean

示例代码

// 实现FactoryBean接口的类
public class MyFactoryBean implements FactoryBean<MyBean> {@Overridepublic MyBean getObject() throws Exception {// 这里可以执行一些自定义逻辑,如创建代理、延迟加载等return new MyBean();}@Overridepublic Class<?> getObjectType() {return MyBean.class;}@Overridepublic boolean isSingleton() {// 指定Bean是否为单例return true;}
}// Spring配置文件(applicationContext.xml)
<bean id="myFactoryBean" class="com.example.MyFactoryBean"/>
// 注意:这里实际上获取的是FactoryBean的getObject()方法返回的对象,而不是FactoryBean本身
// 因此,在获取Bean时,不需要指定FactoryBean的ID,而是直接获取目标Bean的ID(尽管这里我们没有直接定义目标Bean的ID)
// 但由于我们使用了FactoryBean,我们通常不会这样做。在实际应用中,我们可能会通过其他方式(如依赖注入)来使用这个Bean。
// 如果确实需要通过ID获取,可以这样做(但这不是FactoryBean的典型用法):
// <bean id="myBean" factory-bean="myFactoryBean" factory-method="getObject"/>
// 但通常,我们只需要配置FactoryBean,然后在需要MyBean的地方让Spring自动注入即可。

注意:上面的配置文件中关于myBean的声明是不典型的,因为当你配置了一个FactoryBean后,你通常不会再去显式地通过factory-beanfactory-method去获取它产生的对象。相反,Spring会在你需要注入MyBean类型的地方自动使用MyFactoryBean来产生对象。因此,在实际应用中,你可能不会看到像上面那样的myBean声明。

典型用法

在需要使用MyBean的地方,你只需声明一个依赖,Spring会自动使用MyFactoryBean来提供这个依赖。例如:

@Component
public class SomeService {// Spring会自动注入MyFactoryBean产生的MyBean实例private final MyBean myBean;@Autowiredpublic SomeService(MyBean myBean) {this.myBean = myBean;}// ... 使用myBean的方法 ...
}

在这个例子中,SomeService类依赖于MyBean类型,而Spring会自动使用MyFactoryBean来创建并注入这个依赖。

说明

  • FactoryBean接口允许你自定义Bean的创建逻辑。
  • getObject()方法返回实际要注入的Bean实例。
  • getObjectType()方法返回Bean实例的类型。
  • isSingleton()方法指定Bean是否为单例。

注意事项

  • FactoryBean通常用于创建复杂的Bean实例,如代理对象、延迟加载对象等。
  • 确保getObject()方法返回的对象类型与FactoryBean接口中声明的泛型类型一致。
  • 当使用FactoryBean时,通常不需要在配置文件中显式地声明目标Bean的ID,因为Spring会自动处理这部分逻辑。

------分界线--------------------------------------------------------------------------------------------------------------

三、饿汉模式、饱汉模式

在您之前提到的Spring Bean创建方式中,并没有直接包含饿汉模式(Eager Initialization)和饱汉模式(Lazy Initialization)这两种单例模式的实现。饿汉模式和饱汉模式是单例模式在Java中的两种常见实现方式,它们主要用于确保一个类只有一个实例,并提供一个全局访问点来获取该实例。

1、饿汉模式(Eager Initialization)

饿汉模式在类加载时就完成了实例的创建。因此,它是线程安全的,因为JVM在加载类时只会创建一个类实例。但是,如果实例从未被使用过,那么这种提前创建实例的方式可能会浪费资源。

示例代码

public class EagerSingleton {// 在类加载时就创建实例private static final EagerSingleton INSTANCE = new EagerSingleton();// 私有构造方法防止外部实例化private EagerSingleton() {}// 提供全局访问点public static EagerSingleton getInstance() {return INSTANCE;}
}


2、饱汉模式(Lazy Initialization)

饱汉模式在第一次调用getInstance()方法时才创建实例。这种方式节省了资源,但如果多个线程同时调用该方法,则可能会导致多个实例被创建(即不是线程安全的)。为了解决这个问题,通常需要使用同步机制。

示例代码(非线程安全版本)

public class LazySingleton {// 声明实例变量但不立即初始化private static LazySingleton instance;// 私有构造方法防止外部实例化private LazySingleton() {}// 提供全局访问点(非线程安全)public static LazySingleton getInstance() {if (instance == null) {instance = new LazySingleton();}return instance;}
}


示例代码(线程安全版本,使用同步方法)

public class ThreadSafeLazySingleton {// 声明实例变量但不立即初始化private static ThreadSafeLazySingleton instance;// 私有构造方法防止外部实例化private ThreadSafeLazySingleton() {}// 提供全局访问点(线程安全,使用同步方法)public static synchronized ThreadSafeLazySingleton getInstance() {if (instance == null) {instance = new ThreadSafeLazySingleton();}return instance;}
}

或者,使用双重检查锁定(Double-Checked Locking)来优化性能:

public class DoubleCheckedLockingSingleton {// 使用volatile关键字确保instance变量的可见性private static volatile DoubleCheckedLockingSingleton instance;// 私有构造方法防止外部实例化private DoubleCheckedLockingSingleton() {}// 提供全局访问点(线程安全,使用双重检查锁定)public static DoubleCheckedLockingSingleton getInstance() {if (instance == null) {synchronized (DoubleCheckedLockingSingleton.class) {if (instance == null) {instance = new DoubleCheckedLockingSingleton();}}}return instance;}
}


3、异同点

  • 相同点
    • 两者都是单例模式的实现方式。
    • 都提供了全局访问点来获取类的唯一实例。
  • 不同点
    • 实例创建时机:饿汉模式在类加载时就创建实例,而饱汉模式在第一次调用getInstance()方法时才创建实例。
    • 资源消耗:饿汉模式可能会浪费资源(如果实例从未被使用过),而饱汉模式节省了资源。
    • 线程安全性:饿汉模式是线程安全的(因为实例在类加载时就创建了),而未经同步处理的饱汉模式不是线程安全的(可能会导致多个实例被创建)。但是,通过添加同步机制或使用双重检查锁定,可以使饱汉模式变得线程安全。

在Spring框架中,单例Bean的创建通常是由Spring容器管理的,而不是通过饿汉模式或饱汉模式来实现的。Spring容器负责确保每个单例Bean在容器中只有一个实例,并提供依赖注入机制来访问这些Bean。然而,Spring也支持懒加载(Lazy Initialization),这类似于饱汉模式中的延迟创建实例的概念,但它是通过Spring的配置来实现的,而不是通过单例模式本身的实现方式。

(抱歉,最近在面试,粗糙了些。)

(望各位潘安、各位子健/各位彦祖、于晏不吝赐教!多多指正!🙏)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/21139.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在VS-qt的程序中,后期增加PCH预编译功能,提高编译速度

由于前期创建qt程序的时候未勾选pch功能,导致没有启动预编译的功能. 这种情况下需要增加pch功能应该怎么做? 在项目中增加2个文件 stdafx.h和stdafx.cpp文件 stdafx.h增加qt常用头文件 #pragma once //windows #include <windows.h>//qt常用 #include <QObject&g…

天翼云910B部署DeepSeek蒸馏70B LLaMA模型实践总结

一、项目背景与目标 本文记录在天翼云昇腾910B服务器上部署DeepSeek 70B模型的全过程。该模型是基于LLaMA架构的知识蒸馏版本&#xff0c;模型大小约132GB。 1.1 硬件环境 - 服务器配置&#xff1a;天翼云910B服务器 - NPU&#xff1a;8昇腾910B (每卡64GB显存) - 系统内存&…

Python 语法及入门 (超全超详细) 专为Python零基础 一篇博客让你完全掌握Python语法

前言&#xff1a; 本篇博客超级详细&#xff0c;请尽量使用电脑端结合目录阅读 阅读时请打开右侧 “只看目录” 方便阅读 一、什么是Python 1.1 Python的诞生 1989年&#xff0c;为了打发圣诞节假期&#xff0c;Gudio van Rossum吉多 范罗苏姆&#xff08;龟叔&#xff09;决…

【架构】分层架构 (Layered Architecture)

一、分层模型基础理论 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/0365cf0bfa754229bdedca6b472bffc7.png 1. 核心定义 分层架构(Layered Architecture)模型是一种常见的软件设计架构,它将软件系统按照功能划分为不同的层次,每个层次都有特定的职责和功能…

2024年国赛高教杯数学建模C题农作物的种植策略解题全过程文档及程序

2024年国赛高教杯数学建模 C题 农作物的种植策略 原题再现 根据乡村的实际情况&#xff0c;充分利用有限的耕地资源&#xff0c;因地制宜&#xff0c;发展有机种植产业&#xff0c;对乡村经济的可持续发展具有重要的现实意义。选择适宜的农作物&#xff0c;优化种植策略&…

捷米特 JM - RTU - TCP 网关应用 F - net 协议转 Modbus TCP 实现电脑控制流量计

一、项目背景 在某工业生产园区的供水系统中&#xff0c;为了精确监测和控制各个生产环节的用水流量&#xff0c;需要对分布在不同区域的多个流量计进行集中管理。这些流量计原本采用 F - net 协议进行数据传输&#xff0c;但园区的监控系统基于 Modbus TCP 协议进行数据交互&…

遥感影像目标检测:从CNN(Faster-RCNN)到Transformer(DETR)

我国高分辨率对地观测系统重大专项已全面启动&#xff0c;高空间、高光谱、高时间分辨率和宽地面覆盖于一体的全球天空地一体化立体对地观测网逐步形成&#xff0c;将成为保障国家安全的基础性和战略性资源。未来10年全球每天获取的观测数据将超过10PB&#xff0c;遥感大数据时…

iOS事件传递和响应

背景 对于身处中小公司且业务不怎么复杂的程序员来说&#xff0c;很多技术不常用&#xff0c;你可能看过很多遍也都大致了解&#xff0c;但是实际让你讲&#xff0c;不一定讲的清楚。你可能说&#xff0c;我以独当一面&#xff0c;应对自如了&#xff0c;但是技术的知识甚多&a…

【核心算法篇十三】《DeepSeek自监督学习:图像补全预训练方案》

引言:为什么自监督学习成为AI新宠? 在传统监督学习需要海量标注数据的困境下,自监督学习(Self-Supervised Learning)凭借无需人工标注的特性异军突起。想象一下,如果AI能像人类一样通过观察世界自我学习——这正是DeepSeek图像补全方案的技术哲学。根据,自监督学习通过…

轻松搭建本地大语言模型(二)Open-WebUI安装与使用

文章目录 前置条件目标一、安装 Open-WebUI使用 Docker 部署 二、使用 Open-WebUI&#xff08;一&#xff09;访问Open-WebUI&#xff08;二&#xff09;注册账号&#xff08;三&#xff09;模型选择&#xff08;四&#xff09;交互 四、常见问题&#xff08;一&#xff09;容器…

零基础学QT、C++(一)安装QT

目录 如何快速学习QT、C呢&#xff1f; 一、编译器、项目构建工具 1、编译器&#xff08;介绍2款&#xff09; 2、项目构建工具 二、安装QT 1、下载QT安装包 2、运行安装包 3、运行QT creator 4、导入开源项目 总结 闲谈 如何快速学习QT、C呢&#xff1f; 那就是项目驱动法&…

vue取消全选功能按钮注意事项

这里这个功能是通过各种条件查出数据,但只取一条数据进行后续业务,虽然每一条数据前面都有多选框,但只需要选一个,所以在业务上分析可以把这个全选按钮取消掉 这里不是简单的把多选组件的selection-change"handleSelectionChange"和handleSelectionChange方法去掉,因…

【再读】2501.12948/DeepSeek-R1通过强化学习提升大型语言模型(LLMs)的推理能力

DeepSeek-R1-Zero展示了在没有监督数据的情况下&#xff0c;通过RL可以发展出强大的推理能力。DeepSeek-R1通过引入冷启动数据和多阶段训练&#xff0c;进一步提升了推理性能&#xff0c;达到了与OpenAI-o1-1217相当的水平。此外&#xff0c;通过蒸馏技术&#xff0c;将DeepSee…

校园网架构设计与部署实战

一、学习目标 掌握校园网分层架构设计原则 理解多业务VLAN规划方法 学会部署认证计费系统 实现基础网络安全防护 二、典型校园网场景 需求分析&#xff1a;某中学需建设新型校园网络 覆盖教学楼/宿舍/图书馆三区域 区分教师/学生/访客网络权限 满足2000终端并发接入 …

leetcode:942. 增减字符串匹配(python3解法)

难度&#xff1a;简单 由范围 [0,n] 内所有整数组成的 n 1 个整数的排列序列可以表示为长度为 n 的字符串 s &#xff0c;其中: 如果 perm[i] < perm[i 1] &#xff0c;那么 s[i] I 如果 perm[i] > perm[i 1] &#xff0c;那么 s[i] D 给定一个字符串 s &#xff0…

数仓搭建(hive):DWS层(服务数据层)

DWS层示例: 搭建日主题宽表 需求 维度 步骤 在hive中建数据库dws >>建表 CREATE DATABASE if NOT EXISTS DWS; 建表sql CREATE TABLE yp_dws.dws_sale_daycount( --维度 city_id string COMMENT 城市id, city_name string COMMENT 城市name, trade_area_id string COMME…

网工项目实践2.8 IPv6设计及网络优化需求分析及方案制定

本专栏持续更新&#xff0c;整一个专栏为一个大型复杂网络工程项目。阅读本文章之前务必先看《本专栏必读》。 全网拓扑展示 一.IPV6部署规划 在北京总部&#xff0c;为了迎接未来网络的发展&#xff0c;规划在BJ_G2、BJ_G3、BJ_C1、BJ_C2之间运行IPv6协议&#xff0c;以建立I…

50页PDF|数字化转型成熟度模型与评估(附下载)

一、前言 这份报告依据GBT 43439-2023标准&#xff0c;详细介绍了数字化转型的成熟度模型和评估方法。报告将成熟度分为五个等级&#xff0c;从一级的基础转型意识&#xff0c;到五级的基于数据的生态价值构建与创新&#xff0c;涵盖了组织、技术、数据、资源、数字化运营等多…

DeepSeek 接入PyCharm实现AI编程!(支持本地部署DeepSeek及官方DeepSeek接入)

前言 在当今数字化时代&#xff0c;AI编程助手已成为提升开发效率的利器。DeepSeek作为一款强大的AI模型&#xff0c;凭借其出色的性能和开源免费的优势&#xff0c;成为许多开发者的首选。今天&#xff0c;就让我们一起探索如何将DeepSeek接入PyCharm&#xff0c;实现高效、智…

阐解WiFi信号强度

WiFi信号强度是指无线网络信号的强度&#xff0c;通常以负数dB&#xff08;分贝&#xff09;来表示。信号越强&#xff0c;dB值越接近零。WiFi信号强度直接影响你的网络速度、稳定性和连接的可靠性。简单来说&#xff0c;WiFi信号越强&#xff0c;你的设备与路由器之间的数据传…