Spring中FactoryBean的高级用法实战

news2024/12/21 20:01:03
❃博主首页 : 「码到三十五」 ,同名公众号 :「码到三十五」,wx号 : 「liwu0213」
☠博主专栏 : <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关>
♝博主的话 : 搬的每块砖,皆为峰峦之基;公众号搜索「码到三十五」关注这个爱发技术干货的coder,一起筑基

文章目录

      • 前言
      • 基本用法
      • 创建多例对象
      • 创建代理
      • 获取原始 FactoryBean
      • 利用 SPI 获取对象
      • ServiceListFactoryBean获取所有SPI对象
      • FactoryBean应用场景
          • 1. 延迟初始化
          • 2. 依赖注入的高级用法
          • 3. 集成第三方库
          • 4. 自定义作用域
          • 5. 工厂方法的封装
          • 6. 与AOP集成
          • 7. 复杂依赖的解耦

前言

FactoryBean 是 Spring 框架中的一个高级特性,它允许开发者通过自定义的方式控制对象的创建过程。当需要编写复杂的初始化逻辑,而这些逻辑不适合直接放在类的构造函数或初始化方法中时,FactoryBean 提供了一个很好的解决方案。通过实现 FactoryBean 接口,可以在一个单独的方法(通常是 getObject())中封装所有的初始化逻辑,并将这个逻辑的结果(即对象实例)返回给 Spring 容器。

FactoryBean 接口定义了三个关键方法:

  • T getObject(): 返回由该工厂创建的对象的实例。
  • boolean isSingleton(): 指定返回的实例是否为单例。
  • Class<?> getObjectType(): 返回 getObject() 方法返回的对象类型。

Spring 框架内部广泛使用 FactoryBean,提供了超过50个 FactoryBean 的实现,用于创建和配置各种复杂的对象。

下面基于 UserService 类,通过几个实战案例来展示 FactoryBean 的不同用法。


class UserService {
  public void save() {
     System.out.println("save user ...") ;
  }
}

基本用法

在这个例子中,我们创建了一个简单的 UserServiceFactoryBean,用于创建 UserService 的实例。

@Component
public class UserServiceFactoryBean implements FactoryBean<UserService> {
    @Override
    public UserService getObject() throws Exception {
        return new UserService();
    }

    @Override
    public Class<?> getObjectType() {
        return UserService.class;
    }

    @Override
    public boolean isSingleton() {
        return true; // 默认返回单例
    }
}

使用方式:

@Resource
private UserService userService; // 直接注入

// 或者通过 ApplicationContext 获取
ApplicationContext context = ...;
UserService us = context.getBean(UserService.class);

创建多例对象

isSingleton() 方法返回 false,以创建多例对象。

@Override
public boolean isSingleton() {
    return false; // 返回非单例
}

此时,每次通过 Spring 容器获取的 UserService 实例都将是新的,以下两个Controller中注入的UserService将是两个不同的对象:


@Component
public class UserController {
  @Resource
  private UserService userService ;
}
@Component
public class CommonService {
  @Resource
  private UserService userService ;
}

创建代理

使用 FactoryBean 创建代理对象是一种常见用法,尤其是在需要为对象添加横切关注点(如日志、事务管理等)时。

@Override
public PersonService getObject() throws Exception {
    ProxyFactory factory = new ProxyFactory(new UserService());
    factory.addAdvice(new MethodInterceptor() {
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("Before method call");
            Object result = invocation.proceed();
            System.out.println("After method call");
            return result;
        }
    });
    return (UserService) factory.getProxy();
}

获取原始 FactoryBean

有时候,可能需要获取 FactoryBean 本身而不是它创建的对象。

// 通过类型获取
UserServiceFactoryBean factoryBean = context.getBean(UserServiceFactoryBean.class);

// 或者通过名称获取,添加 '&' 前缀
UserServiceFactoryBean factoryBeanByName = context.getBean("&userServiceFactoryBean");

利用 SPI 获取对象

Spring 提供的 ServiceFactoryBeanServiceListFactoryBean 可以方便地用于基于 SPI 机制的服务加载。

@Configuration
public class AppConfig {
    @Bean
    public ServiceFactoryBean<DAO> daoFactoryBean() {
        ServiceFactoryBean<DAO> fb = new ServiceFactoryBean<>();
        fb.setServiceType(Partition.class);
        return fb;
    }
}

META-INF/services 目录下创建与 Partition 接口全限定名对应的文件,列出所有实现类的全限定名。Spring 将加载并实例化这些实现类,并通过 daoFactoryBean 提供访问。


com.diguobobo.helper.IdPartition
com.diguobobo.helper.DatePratition

容器中注入Partition时,将得到这里的第一个IdPartition实例。

ServiceListFactoryBean获取所有SPI对象

如果你需要获取 SPI 接口的所有实现,而不是单个实现,可以使用 ServiceListFactoryBean。这个 Bean 工厂会返回一个包含所有 SPI 实现的列表。配置方式与 ServiceFactoryBean 类似,但返回的将是一个列表,而不是单个对象。

@Configuration  
public class AppConfig {  
    @Bean  
    public ServiceListFactoryBean<DAO> daoListFactoryBean() {  
        ServiceListFactoryBean<DAO> fb = new ServiceListFactoryBean<>();  
        fb.setServiceType(Partition.class);  
        return fb;  
    }  
}  
  
// 使用时注入List<Partition>  
@Autowired  
private List<Partition> daos;

FactoryBean应用场景

1. 延迟初始化

默认情况下,Spring容器中的Bean会在容器启动时进行初始化。但是,通过FactoryBean,你可以控制对象的创建时机,直到真正需要该对象时才进行创建。这可以通过在FactoryBean中实现特定的逻辑来延迟调用getObject()方法实现。

2. 依赖注入的高级用法

FactoryBean允许开发者在依赖注入过程中进行更精细的控制。例如,你可以根据特定的条件动态地选择不同的Bean实例进行注入,或者根据环境变量、配置属性等动态地创建Bean实例。

3. 集成第三方库

当需要将第三方库中的对象集成到Spring容器中时,如果这些对象的创建过程比较复杂或者不符合Spring的默认Bean创建规则,你可以通过实现FactoryBean来封装这些复杂的创建逻辑。这样,就可以像使用其他Spring Bean一样使用这些第三方库中的对象了。

4. 自定义作用域

虽然FactoryBean本身并不直接提供作用域的定义(作用域通常由Spring容器管理),但你可以通过FactoryBean来控制对象的创建过程,从而实现自定义作用域的效果。例如,可以通过FactoryBean来管理具有自定义生命周期的对象,如数据库连接、网络会话等。

5. 工厂方法的封装

有时可能需要使用某个类的静态工厂方法来创建对象实例。虽然Spring支持通过@Bean注解来引用静态工厂方法,但实现FactoryBean提供了一种更加封装和灵活的方式来处理这种情况。你可以在FactoryBean中实现调用静态工厂方法的逻辑,并将FactoryBean本身注册为Spring容器中的Bean。

6. 与AOP集成

FactoryBean可以与Spring的AOP(面向切面编程)功能集成,用于在对象创建过程中应用横切关注点(如事务管理、日志记录等)。虽然通常这些横切关注点会应用在Bean的方法调用上,但通过在FactoryBean中实现特定的逻辑,你也可以在对象创建过程中应用这些关注点。

7. 复杂依赖的解耦

复杂的应用中,Bean之间可能存在复杂的依赖关系。通过实现FactoryBean,你可以将这些复杂的依赖关系封装在FactoryBean内部,从而简化Bean之间的依赖关系。这样,其他Bean只需要依赖于FactoryBean创建的实例,而不需要关心这些实例背后的复杂创建逻辑和依赖关系。


关注公众号[码到三十五]获取更多技术干货 !

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

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

相关文章

AT3340-6T杭州中科微BDS定位授时板卡性能指标

AT3340-6T是一款高性能多系统卫星定位安全授时板卡&#xff0c;可通过配置支持各个单系统的定位授时。 外观尺寸&#xff1a; 电气参数 应用领域&#xff1a; 通信基站授时 电力授时 广播电视授时 轨道系统授时 金融系统授时 其他授时应用 注意事项&#xff1a; 为了充分发挥…

nvidia-smi命令视图含义

第一部分&#xff1a;NVIDIA-SMI 标题 ---------------------------------------------------------------------------------------- | NVIDIA-SMI 555.42.06 Driver Version: 555.42.06 CUDA Version: 12.5 | ------------------------------------------------------------…

ML 系列:机器学习和深度学习的深层次总结(01)

​ 文章目录 一、说明二、人工智能和机器学习三、机器学习的类型四、结论 一、说明 欢迎学习机器学习系列。这门综合课程目前包括40个部分&#xff0c;指导您了解机器学习、统计和数据分析的基本概念和技术。以下是到目前为止涵盖的关键主题的简要概述&#xff1a; 1 机器学习…

C与汇编之间的相互调用(29)

1 先来看一下 基本的调用规则。 注意&#xff1a; 程序通过 r1 -r4 来保存 传递的参数&#xff0c;如果 超过了 4个参数怎么办&#xff0c; 那就 放到栈里面。 注意&#xff1a; 堆栈是满递减&#xff0c; FD。 子程序的返回结果 会放到R0 里面。 2 然后是 c 语言调用 汇编语言…

如何最好地制定自动化测试策略

尽管不能否认手动测试的价值&#xff0c;自动化测试的需求却在不断增长。自动化测试可以为公司和团队带来许多好处&#xff1a;时间效率高、覆盖面广。 如何最好地制定自动化测试策略呢&#xff1f; 在本文中&#xff0c;我将展示测试自动化策略的所有7个阶段中的一些最佳实践…

gpt4最新保姆级教程

如何使用 WildCard 服务注册 Claude3 随着 Claude3 的震撼发布&#xff0c;最强 AI 模型的桂冠已不再由 GPT-4 独揽。Claude3 推出了三个备受瞩目的模型&#xff1a;Claude 3 Haiku、Claude 3 Sonnet 以及 Claude 3 Opus&#xff0c;每个模型都展现了卓越的性能与特色。其中&a…

LLM - 理解 多模态大语言模型 (MLLM) 的发展与相关技术 (一)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/142063880 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 多模态…

揭秘世界上那些同时横跨两大洲的国家

我们在《世界人口过亿的一级行政区分布》盘点全球是那些人口过亿的一级行政区。 现在我们介绍五个横跨两州的国家&#xff0c;并整理七大洲和这些国家的KML矢量数据分析分享给大家&#xff0c;如果你需要这些数据&#xff0c;请在文末查看领取方式。 世界上横跨两大洲的国家 …

【Python报错已解决】SyntaxError: positional argument follows keyword argument

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 前言一、问题描述1.1 报错示例1.2 报错分析1.3 解决思路 二、解决方法2.1 方法一&#xff1a;调整参数顺序2.2 步骤二…

excel分列

Excel中有这么几列&#xff0c;希望将每一列内容再分出3列&#xff1a; 可以通过以下步骤在 Excel 表格中将 B 到 F 列的内容拆分为每列的 3 列&#xff0c;分别为 pred_label、pred_score 和 pred_class&#xff1a; 确定数据结构&#xff1a;假设 B 列到 F 列中的内容都是按类…

洛谷 P10798 「CZOI-R1」消除威胁

题目来源于&#xff1a;洛谷 题目本质&#xff1a;贪心&#xff0c;st表&#xff0c;单调栈 解题思路&#xff1a;由于昨天联练习了平衡树&#xff0c;我就用平衡树STL打了个暴力&#xff0c;超时得了30分 这是暴力代码&#xff1a; #include<bits/stdc.h> using name…

小琳AI课堂:多模态模型的训练与应用

引言 大家好&#xff0c;这里是小琳AI课堂。今天我们将探讨一个热门且前沿的话题——多模态模型的训练与应用。让我们一起走进这个复杂而精致的艺术创作过程&#xff01; 训练关键步骤 1. 数据收集与预处理 准备工作&#xff1a;从多种来源和模态收集数据&#xff0c;如文…

苍穹外卖()

day1 软件开发整体介绍 软件开发流程&#xff1a;需求分析&#xff08;需求规格说明书、产品原型&#xff09;->设计&#xff08;UI设计、数据库设计、接口设计&#xff09;->编码&#xff08;项目代码&#xff0c;单元测试&#xff09;->测试&#xff08;测试用例、…

C++:入门篇(补充C语言中的不足)

前言 这篇文章是C的第一篇文章&#xff0c;主要是补充C语言中存在的不足而扩展的一些新的语法&#xff0c;有了这篇文章作为杂序&#xff0c;后面再介绍其他内容就要清晰地多 C&#xff1a;入门篇 一、namespace 命名空间&#xff08;一&#xff09;域的概念&#xff08;二&…

【深度学习讲解笔记】第1章-机器学习基础(2)

模型与函数构造 之前讲到&#xff0c;模型是由机器学习决定参数值的函数&#xff0c;通过训练&#xff0c;机器可以找出最好的一组参数使得函数的输出最优。常见的模型有线性模型&#xff0c;指数模型&#xff0c;对数模型等。在线性模型中&#xff0c;w和b是可学习的参数&…

【Hadoop|HDFS篇】DataNode概述

1. DataNode的工作机制 1&#xff09;一个数据块在DataNode上以文件形式存储在磁盘上&#xff0c;包括两个文件&#xff0c;一个是数据本身&#xff0c;一个是元数据包括数据块的长度&#xff0c;块数据的校验和&#xff0c;以及时间戳。 2&#xff09;DataNode启动后向NameNod…

象过河在线进销存软件——简单、高效、智能,让生意更简单!

仓库管理&#xff0c;曾是我心中的一大“乱麻”——库存不清、数据混乱、出入库效率低... 但自从邂逅了【象过河在线进销存软件】&#xff0c;一切都变得那么简单、高效、智能&#xff01; 象过河在线进销存软件优势&#xff1a; 1、界面简洁&#xff0c;流程简单 作为亲身体…

【时时三省】(C语言基础)指针进阶 例题4

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 strlen是求字符串长度 这个需要算上&#xff3c;0 第一个arr 是打印6 因为它加上&#xff3c;0是有六个元素 第二个arr0 数组名相当于首元素的地址 a的地址加0还是a的地址 所以这个地方还是…

Linux日志-kdump日志

作者介绍&#xff1a;简历上没有一个精通的运维工程师。希望大家多多关注作者&#xff0c;下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 Linux 系统中的日志是记录系统活动和事件的重要工具&#xff0c;它们可以帮助管理员监视系统状态、调查问题以及了解系统运行…

IDEA Maven 源修改为国内阿里云镜像的正确方式

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storm…