究竟FactoryBean是什么?深入理解Spring的工厂神器

文章目录

    • 前言
    • 什么是FactoryBean?
    • 如何使用FactoryBean?
    • 我们常见的FactoryBean
    • BeanFactory 和 FactoryBean?
    • FactoryBean后续?MapperFactoryBean

在这里插入图片描述

前言

在Spring框架中,bean的创建通常交由Spring IoC容器负责,它提供了丰富的方式来创建和管理bean的生命周期。在众多的功能中,FactoryBean 以一种特别的方式出现,不仅让我们能够控制bean的创建过程,还使得更复杂的初始化逻辑变得简洁清晰。接下来,让我们 一步步地走进FactoryBean的世界,并通过案例解析来透彻理解它在Spring应用中的使用。

什么是FactoryBean?

FactoryBean 是Spring提供的一种特殊的bean,使用它可以生成某些需要复杂初始化过程的bean对象。当配置某个bean实现了FactoryBean接口时,该bean返回的对象不是FactoryBean本身,而是FactoryBean#getObject()方法返回的对象,这就提供了一种扩展的可能,我们可以在这个方法里定制创建逻辑。

它与Spring其他bean的主要区别在于,FactoryBean负责产生其他bean实例。也即当我们从IOC容器中获取一个FactoryBean时,我们得到的是它创建的那个bean的实例,而不是FactoryBean的实例本身。

如何使用FactoryBean?

使用FactoryBean的情况一般是:

  • 当我们注册的bean需要一系列复杂的初始化步骤。
  • 我们需要创建一个非单例的bean,并且需要在运行时彻底实现某些操作,或者我们需要对bean实例进行精细控制。

实现FactoryBean非常简单,只需要:

  1. 声明一个类实现FactoryBean接口。
  2. 实现getObject()方法来定义创建对象的逻辑。
  3. 实现getObjectType()方法返回创建对象的类型。
  4. 通过实现isSingleton()方法来决定你的bean是原型还是单例。

假设我们有一个UserService类,它的创建过程比较复杂,需要从数据库中获取一些配置信息。我们可以使用FactoryBean来简化这个过程。

  • 实现UserServiceFactoryBean类:
public class UserServiceFactoryBean implements FactoryBean<UserService> {private String config;// getter and setter methods...@Overridepublic UserService getObject() throws Exception {// 这里可以放一些复杂的逻辑,比如和其他系统交互,或者执行一些耗时操作UserService userService = new UserService();userService.setConfig(this.config);return userService;}@Overridepublic Class<?> getObjectType() {return UserService.class;}@Overridepublic boolean isSingleton() {return true;}
}
  • 配置UserServiceFactoryBean:
<bean id="userService" class="com.example.UserServiceFactoryBean"><property name="config" value="some config"/>
</bean>
  • 使用UserServiceFactoryBean: 这里会通过UserServiceFactoryBean获取得到UserService
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("userService");

我们常见的FactoryBean

FactoryBean 的常见使用场景包括但不限于:

  • 创建复杂的Bean,例如涉及到复杂配置和初始化流程的Bean。
  • 延迟初始化资源或对象,因为getObject将在实际需要时被调用—比如解决循环依赖时,使用三级缓存存放的ObjectFactory用于提前AOP。
  • 返回不同实例的代理,基于调用的上下文—ProxyFactoryBean创建代理对象。

其实很多场景的FactoryBean 可能都见过,只是可能没去总结归纳。我给小伙伴们举几个例子。

在 SSM 项目中,如果我们要配置 MyBatis 到项目中,一般需要配置下面这个 Bean:

<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactoryBean"><property name="dataSource" ref="dataSource"/><property name="typeAliasesPackage" value="com.apple"/><property name="mapperLocations"><list><value>classpath*:com/apple/mapper/*.xml</value></list></property>
</bean>

我们在配置 Shiro 的时候,一般都要配置如下 Bean:

<bean class="org.apache.shiro.spring.web.ShiroFilterFactoryBean" id="shiroFilter"><property name="securityManager" ref="securityManager"/><property name="loginUrl" value="/login"/><property name="successUrl" value="/index"/><property name="unauthorizedUrl" value="/unauthorizedUrl"/><property name="filterChainDefinitions"><value>/index=anon/doLogin=anon/hello=user/**=authc</value></property>
</bean>

如果我们前端传递的参数是 key-value 格式,并且有一个日期,那么小伙伴们知道,服务端 SpringMVC 默认无法处理这个日期,需要配置一个日期转换器,一般我们在 Spring 容器中添加如下 Bean

<bean class="org.springframework.format.support.FormattingConversionServiceFactoryBean" id="conversionService"><property name="converters"><set><ref bean="myDateConverter"/></set></property>
</bean>
<mvc:annotation-driven conversion-service="conversionService"/>

我们观察上面三个 Bean 有一个共同的特点,那就是 Bean 的名字都是 xxxFactoryBean。

为什么要用 xxxFactoryBean 而不直接把需要的 Bean 注入到 Spring 容器中去呢?以 MyBatis 为例:

手动配置过 MyBatis 的小伙伴应该都知道,MyBatis 有两个重要的类,一个是 SqlSessionFactory,还有一个是 SqlSession,通过 SqlSessionFactory 可以获取到一个 SqlSession。

SqlSessionFactoryBean核心代码如下:其创建SqlSessionFactory复杂逻辑都在 afterPropertiesSet()

public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {private SqlSessionFactory sqlSessionFactory;@Overridepublic SqlSessionFactory getObject() throws Exception {if (this.sqlSessionFactory == null) {afterPropertiesSet();}return this.sqlSessionFactory;}@Overridepublic Class<? extends SqlSessionFactory> getObjectType() {return this.sqlSessionFactory == null ? SqlSessionFactory.class : this.sqlSessionFactory.getClass();}@Overridepublic boolean isSingleton() {return true;}
}

大家看一下,SqlSessionFactoryBean 需要实现 FactoryBean 接口,并且在实现接口的时候指定泛型是 SqlSessionFactory,也就是 SqlSessionFactoryBean 最终产出的 Bean 是 SqlSessionFactory。

这就是 FactoryBean 的特点,由于某一个 Bean 的初始化过于复杂,那么就可以通过 FactoryBean 来帮助注册到 Spring 容器中去。

BeanFactory 和 FactoryBean?

  • BeanFactory 是 Spring 框架的核心接口之一,用于管理和获取应用程序中的 Bean 实例。它是一个工厂模式的实现,负责创建、配置和管理 Bean 对象。BeanFactory 是 Spring IoC 容器的基础,它可以从配置元数据(如 XML 文件)中读取 Bean 的定义,并在需要时实例化和提供这些 Bean。
  • FactoryBean 是一个特殊的 Bean,它是一个工厂对象,用于创建和管理其他 Bean 的实例。FactoryBean 接口定义了一种创建 Bean 的方式,它允许开发人员在 Bean 的创建过程中进行更多的自定义操作。通过实现 FactoryBean 接口,开发人员可以创建复杂的 Bean 实例,或者在 Bean 实例化之前进行一些额外的逻辑处理。

区别在于,BeanFactory 是 Spring 框架的核心接口,用于管理和提供 Bean 实例,而 FactoryBean 是一个特殊的 Bean,用于创建和管理其他 Bean 的实例。FactoryBean 在 Bean 的创建过程中提供更多的自定义能力,允许进行额外的逻辑处理。

确切地烙印在记忆中:当你遇到需求类似"我需在Runtime时动态地配置我的bean" 或者 "我需要确保我的bean是复杂生产步骤下的产物"时,那么FactoryBean就是你的不二之选。

FactoryBean后续?MapperFactoryBean

使用过Spring Boot的同学都知道,当我们需要扫描Mapper的时候,需要添加@MapperScan注解完成对Mapper对象的扫描,@MapperScan导入MapperScannerRegistrar类完成扫描。

但是Mapper类都是接口,无法被实例化,那么为什么在Spring中能够直接注入Mapper对象呢?

实际上Mybatis是通过FactoryBean对象(MapperFactoryBean)创建Mapper对象的代理对象,完成Mapper接口的注入。

这里篇幅有限,后面我再进行解析。。。

参考文章:

https://mp.weixin.qq.com/s/r3rnVhU8vr58Cw__UWOVLA

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

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

相关文章

【从亮机卡开始的云炼丹】环境配置记录debug

要更改Anaconda环境的默认路径到D盘 可以按照以下步骤操作&#xff1a; 1. 打开Anaconda Prompt&#xff08;或者命令行窗口&#xff09;。 2. 输入以下命令更改Anaconda环境的默认路径到D盘&#xff1a; conda config --set envs_dirs D:\Anaconda\envs 这将把Anaconda环境…

汽车租聘管理与推荐系统Python+Django网页界面+协同过滤推荐算法

一、介绍 汽车租聘管理与推荐系统。本系统使用Python作为主要编程语言&#xff0c;前端采用HTML、CSS、BootStrap等技术搭建前端界面&#xff0c;后端采用Django框架处理用户的请求。创新点&#xff1a;使用协同过滤推荐算法实现对当前用户个性化推荐。 其主要功能如下&#x…

机器学习比较 - 基于OpenCV进行图像向量的提取

一、简述 在将图像输入机器学习算法之前,通常对图像执行的预处理步骤之一是将它们转换为特征向量。将图像转换为特征向量有几个优点,可以使机器学习算法更加高效的运行。 在将图像转换为特征向量的不同技术中,经常与不同机器学习算法结合使用的两种最流行的技术是定向梯度直…

设计模式—依赖倒置原则(DIP)

1.概念 依赖倒置原则&#xff08;Dependence Inversion Principle&#xff09;是程序要依赖于抽象接口&#xff0c;不要依赖于具体实现。简单的说就是要求对抽象进行编程&#xff0c;不要对实现进行编程&#xff0c;这样就降低了客户与实现模块间的耦合。 通俗的讲&#xff1…

1-Python与设计模式--单例模式

1-Python与设计模式–单例模式 一、总线 总线是计算机各种功能部件或者设备之间传送数据、控制信号等信息的公共通信解决方案之一。 现假设有如下场景&#xff1a;某中央处理器&#xff08;CPU&#xff09;通过某种协议总线与一个信号灯相连&#xff0c;信号灯有64种颜色可以…

SpringBoot校验List失效解决方法

文章目录 SpringBoot校验List失效解决方法附&#xff1a;校验基本数据类型和String类型的方法参数时也需要在类上加Validated SpringBoot校验List失效解决方法 失效场景示例代码&#xff1a; RestController RequestMapping("/v1/jx/flowSummary") Slf4j public cl…

【React】打包优化-配置CDN

CDN 是一种内容分发网络服务&#xff0c;当用户请求网站内容时&#xff0c;由离用户最近的服务器将缓存的资源内容传递给用户。 哪些资源可以放到CDN服务器&#xff1f;&#xff08;比如react、 react-dom&#xff09; 体积较大&#xff0c;需要利用CDN文件在浏览器的缓存特性…

用python实现文字转语音的5个较好用的模块

文章目录 一. 用 gtts 模块二. 用pyttsx3模块基本使用直接朗读更改语音、速率和音量 三. baidu-aip四. pywin32五. speech 一. 用 gtts 模块 参考文档&#xff1a;https://gtts.readthedocs.io/en/latest/ 使用前需要先安装&#xff1a;pip3 install gtts &#xff0c;样例如…

抖音小店开店指南:流程、准备和营销策略一站解析

抖音小店已成为一个热门的社交电商平台&#xff0c;为商家提供了一个快速、方便、低成本的开店通道。下面四川不若与众将介绍抖音小店开店的流程和需要准备的工作&#xff0c;帮助商家顺利开启自己的电商之路。 一、开店准备工作&#xff1a; 1. 产品准备&#xff1a;确定出售…

保护好你的小鸡!保姆级服务器安全教程!

为什么要做安全防护 Linux 服务器的安全防护是一个纷繁复杂的巨大课题。无数的网站、APP、服务、甚至线下基础设施都建立在 Linux 的基石之上,这背后牵涉到巨大的经济利益和商业价值,当然也就意味着黑灰产有巨大的攻击动力。但是这些服务是如此重要、根本不允许出现重大的安…

Java王者荣耀

一、创建项目 二、代码 package com.sxt;import javax.swing.*; import java.awt.*;public class Background extends GameObject {public Background(GameFrame gameFrame) {super(gameFrame);// TODO Auto-generated constructor stub}Image bg Toolkit.getDefaultToolkit(…

mac Terminal config proxy 【mac 终端配置代理】

vi ~/.bash_profile alias proxyexport http_proxy127.0.0.1:1088;export https_proxy$http_proxy alias proxyOffunset http_proxy;unset https_proxy生效 source ~/.bash_profile而从 macOS Catalina 版开始&#xff0c;Mac 将使用 zsh 作为默认的 Shell 终端。要对其进行配…

Mac 最佳使用指南

如何在macOS系统安装根证书mac Terminal config proxy 【mac 终端配置代理】iPhone 安装 iOS 17公测版&#xff08;Public Beta)macOS 最佳命令行客户端&#xff1a;iTermMac 配置与 Linux 互信Mac mini 外接移动硬盘无法写入或者无法显示的解决方法如何在 macOS 美化 iterm2 &…

5 动态规划解分割等和子串

来源&#xff1a;LeetCode第416题 难度&#xff1a;中等 描述&#xff1a;给你一个只包含正整数的非空数组nums,请你判断是否可以将这个数组分割成两个子集&#xff0c;使得两个子集的元素和相等 分析&#xff1a;相当于从nums数组中选取一些元素&#xff0c;使得他们的和为…

数据库基础教程之数据库的创建(二)

双击打开Navicat,点击:文件-》新建连接-》PostgreSQL 在下图新建连接中输入各参数,然后点击:连接测试,连接成功后再点击确定。 创建数据表   3.1 方法1   3.1.1.双击你的数据库-》双击public-》双击选中表-》右键-》新建表-》常规 3.1.2.设置字段信息   双击选中创建…

软件实施面试题

一&#xff0c;Java 笔试题 1、掌握 Java 那些常用排序算法 冒泡排序&#xff08;Bubble Sort&#xff09; 选择排序&#xff08;Selection Sort&#xff09; 插入排序&#xff08;Insertion Sort&#xff09; 希尔排序&#xff08;Shell Sort&#xff09; 归并排序&#xff…

C++ vector迭代器失效

STL中vector迭代器失效常见错误写法示例 最近在看STL容器失效的例子&#xff0c;涉及到vector数组迭代器失效的问题&#xff0c;如果不注意使用&#xff0c;很容易出现问题&#xff0c;我们先来看一下一个简单的示例程序&#xff0c;在数组nums中删除大于50的元素&#xff0c;…

【方块消消乐】方块消除游戏-微信小程序开发流程详解

有做过俄罗斯方块游戏小程序的经验&#xff0c;这次有做了一个消灭方块的游戏&#xff0c;实现过程很顺利&#xff0c;游戏看着和之前做的俄罗斯方块游戏很像&#xff0c;这里调整了玩法&#xff0c;试玩感觉还可以&#xff0c;接下来给大家讲一讲消灭方块游戏开发过程。 俄罗斯…

(离散数学)命题逻辑推理一:直接推理

P说明这一行是前提&#xff0c;T说明这一行是结论 &#xff0c;I说明该结论是由推导而来&#xff0c;E说明该结论是由化简而来&#xff0c;括号里的数字是推导这一结论需要的条件序号。 这种写法只是将重言蕴含的论证的思路进行了梳理 &#xff0c;前件为真则后件为真、后件为假…

scrollY offsetTop pageYOffset scrollTop

当涉及到页面滚动时&#xff0c;这些属性和方法扮演了不同的角色。让我来解释一下它们的含义和区别&#xff1a; scrollY 是 window 对象的一个只读属性&#xff0c;它返回文档在垂直方向已滚动的像素值。它提供了当前滚动位置相对于文档顶部的距离。 获取方式&#xff1a;可以…