Spring框架FactoryBean接口的作用和应用

一、FactoryBean源码解读

FactoryBean<T> 是 Spring 框架 beans.factory包中的一个接口,从字面意思可以理解为工厂bean,它是干什么的,类名上的泛型又是指什么,有什么作用?

注释看不懂没关系,先看一下它有哪些方法。

public interface FactoryBean<T> {
    // 获取实例
    @Nullable
    T getObject() throws Exception;
    // 获取实例的class类型
    @Nullable
    Class<?> getObjectType();
    // 实例默认为单例
    default boolean isSingleton() {
        return true;
    }
}

方法看完了,还是不知道它能干嘛,继续看它的子类。

子类真多,一个屏幕放不下,找几个看看。

二、FactoryBean的子类

先看两个简单的实现类:

1、AuthenticationManagerFactoryBean类

AuthenticationManagerFactoryBean是spring-boot-starter-security 框架中的一个类,这个类实现了FactoryBean<AuthenticationManager>, BeanFactoryAware 两个接口的功能。

BeanFactoryAware 接口在《Spring框架Aware接口的作用和应用》一文中已经介绍过,它是用于在当前类初始化时获取 BeanFactory 接口以供当前类使用的。

FactoryBean<AuthenticationManager>的泛型位置放置了一个类AuthenticationManager。

AuthenticationManagerFactoryBean实现了FactoryBean接口中3个方法

在getObject() 方法中创建了AuthenticationManager实例并返回。

在该方法的最后一行代码可以看出,AuthenticationManager的实例是交给ProviderManager 对象管理的。

因此,在getObjectType()方法中返回的是ProviderManager对象的class。

在 isSingleton()方法中返回的依旧是单例模式。

从以上代码的分析,我们可以得出一个结论,AuthenticationManagerFactoryBean类是用来创建AuthenticationManager对象实例的工厂bean类。

2、CronTriggerFactoryBean类

CronTriggerFactoryBean是Spring框架定时任务 org.springframework.scheduling.quartz 包中的一个类,这个类实现了FactoryBean<CronTrigger>, BeanNameAware, InitializingBean 3个接口的功能。

BeanNameAware 是用于在当前类初始化时获取当前类的bean名称的。

InitializingBean 接口是用于重写初始化方法的。

FactoryBean<CronTrigger>的泛型位置放置了一个类CronTrigger。 

CronTrigger是定时任务的表达式对象。 

在重写的 afterPropertiesSet() 初始化方法中,new 了一个 CronTriggerImpl对象并返回。

CronTriggerImpl位于定时任务框架 org.quartz中,它是CronTrigger的实现类。

接下来就是FactoryBean三个方法的实现:

getObject() 方法中直接初始化方法中创建的cronTrigger变量。

getObjectType()方法返回的是CronTrigger的class,它是CronTriggerImpl的超类。

isSingleton()方法中返回的是单例模式。

从以上代码的分析,我们也可以得出一个结论,CronTriggerFactoryBean类是用来创建CronTriggerFactory对象实例的工厂bean类。

再来看两个复杂一些的抽象类。

3、AbstractFactoryBean<T>抽象类

AbstractFactoryBean<T>实现了FactoryBean<T>, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean 5个接口。

FactoryBean<T>泛型位置的参数还是泛型。

BeanClassLoaderAware接口是用于在当前类初始化时获取类加载对象ClassLoader的。

BeanFactoryAware接口是用于在当前类初始化时获取BeanFactory的。

InitializingBean 接口是用于重写初始化方法的。

DisposableBean 接口是用于重写销毁方法的。

在初始化方法中,如果是单例则进行实例化:


protected abstract T createInstance() throws Exception;
@Override
@Nullable
public abstract Class<?> getObjectType();
@Override
public final T getObject() throws Exception {
    if (isSingleton()) {
        return (this.initialized ? this.singletonInstance : getEarlySingletonInstance());
    }
    else {
        return createInstance();
    }
}

实例化是个抽象方法,由其子类实现具体实例化逻辑。

getObjectType()也是抽象方法,由其子类实现。

getObject()是个final方法,子类不能更改,如果是单例则返回单例实例,否则每次调用返回一个新的实例。

在AbstractFactoryBean抽象类中,我们最关心的FactoryBean中的2个方法,一个由其子类实现,一个由抽象类实现。不管是子类还是抽象类,目的都是一样的。

4、ListFactoryBean类

ListFactoryBean是AbstractFactoryBean<List<Object>>的子类,通过这个头可以看出它是创建一个List集合的。

在getObjectType()方法中,直接返回List集合的class。

在createInstance()方法中,实现了List集合的实例化逻辑。

还有很多抽象类、实现类,我们就不举例了。

从以上3个类我们可以推断出,FactoryBean就是一个创建和管理bean实例的特殊工厂bean。

FactoryBean的子类很多,但是子接口只有一个,我们也看下。

三、SmartFactoryBean子接口和应用

1、SmartFactoryBean源码解读

SmartFactoryBean接口扩展了FactoryBean接口


public interface SmartFactoryBean<T> extends FactoryBean<T> {

    // 是否为原型,默认false
    default boolean isPrototype() {
        return false;
    }

    // 是否提前初始化,默认false
    default boolean isEagerInit() {
        return false;
    }
}

这个接口增加了两个方法:

isPrototype()方法,判断当前要创建的bean实例是否是原型。

isEagerInit()方法,判断当前要创建的bean实例是否提前实例化。

2、FactoryBean和SmartFactoryBean的应用比较

1)定义一个bean


public class MyBean2{
    
    public MyBean2() {
        System.out.println("1、实例化 MyBean2");
    }
   
    public void fun(){
        System.out.println("2、调用  MyBean2 的 fun 方法");
    }
}

2)把MyBean2对象封装到MyBean2FactoryBean中


@Component
public class MyBean2FactoryBean implements SmartFactoryBean<MyBean2>{
    
    private MyBean2 myBean2;
    
    @Override
    public MyBean2 getObject() throws Exception {
        if(myBean2 == null){
            myBean2 = new MyBean2();
        }
        return myBean2;
    }

    @Override
    public Class<?> getObjectType() {
        return MyBean2.class;
    }
    
    @Override
    public boolean isEagerInit() {
        return true;
    }
}

测试FactoryBean接口时,可以把SmartFactoryBean替换成FactoryBean,并把isEagerInit注释掉。

3)测试代码

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.beans.factory.SmartFactoryBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;
/**
 * SmartFactoryBean接口演示代码,是否提前实例化的验证
 * @author 
 * @Description
 *
 */
public class SpringApp5 {
    
    public static void main(String[] args) {   
        
       AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyBean2FactoryBean.class);
      
       MyBean2FactoryBean myBean2FactoryBean = context.getBean(MyBean2FactoryBean.class);
       try {
           System.out.println("还没有调用呢");
            MyBean2 myBean = myBean2FactoryBean.getObject();
            myBean.fun();
       } catch (Exception e) {
            e.printStackTrace();
       }
       context.close();
   }
}

当我们使用 FactoryBean 的时候,Spring 在实例化 Bean 的时候,实例化的是MyBean2FactoryBean 工厂 Bean,MyBean2则是在工厂 Bean中实例化的。

当把工厂bean更改为FactoryBean的时候,运行结果如下:

Creating shared instance of singleton bean 'myBean2FactoryBean'
还没有调用呢
1、实例化 MyBean2
4、调用  MyBean2 的 fun 方法

当把工厂bean更改为SmartFactoryBean的时候,并设置提前实例化时,运行结果如下:

Creating shared instance of singleton bean 'myBean2FactoryBean'1、实例化 MyBean2还没有调用呢4、调用  MyBean2 的 fun 方法

当我们把 isEagerInit() 返回 true时,实例化提前了,没有使用就被实例化了。

最后总结

FactoryBean<T>是一个特殊的bean,用于创建和管理自定义 Bean 实例的工厂bean,其中类名中的泛型就是要创建Bean的类名,如果子类是一个抽象类,那么具体的创建实例过程会延伸到其子类。

FactoryBean<T>定义了一种创建 Bean 的方式,允许在 Bean 的创建过程中进行更多的自定义操作。通过实现 FactoryBean 接口,我们可以创建复杂的 Bean 实例,或者在 Bean 实例化之前进行一些额外的逻辑处理,比如重写初始化方法的InitializingBean等等。

在看源码时,如果看到某个类名是:XxxxFactoryBean,我们就能在瞬间知道这个类是创建Xxxx实例的工厂bean。如果还带有泛型XxxxFactoryBean<T>,就说明这是一个抽象类,具体的创建实例的过程在其子类中。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一键智控,舒适无限:网关在风机盘管智能温控中的应用

风机盘管智能控制系统采用钡铼技术系列无线网关&#xff0c;搭配各类风机设备及传感器组成无线物联中央空调室内机管理系统&#xff0c;实现整个办公楼的空调环境智能化管理。在建筑舒适度的前提下&#xff0c;降低能耗&#xff0c;避免能源浪费。 网关通信接口采用无线传输的…

上班族要怎么挑选智能猫砂盆?今年最受欢迎的牌子都在这里了!

对于上班族来说&#xff0c;猫砂盆里的猫屎到底该如何是好&#xff0c;放到下班回来再铲&#xff0c;猫砂的臭味早就飘满屋子&#xff0c;想立刻铲掉吧&#xff0c;班不要上啦&#xff1f;可是不铲就会生细菌&#xff0c;谁也不想花个几千块去给猫咪看病吧&#xff0c;谁不希望…

PointMamba: A Simple State Space Model for Point Cloud Analysis

1. 论文基本信息 2. 创新点 介绍了第一个状态空间模型 PointMamba&#xff0c;将其应用与点云分析。PointMamba 表现出令人印象深刻的能力&#xff0c;包括结构简单性&#xff08;例如&#xff0c;vanilla Mamba&#xff09;、低计算成本和知识可迁移性&#xff08;例如&#…

大数据处理引擎选型之 Hadoop vs Spark vs Flink

随着大数据时代的到来&#xff0c;处理海量数据成为了各个领域的关键挑战之一。为了应对这一挑战&#xff0c;多个大数据处理框架被开发出来&#xff0c;其中最知名的包括Hadoop、Spark和Flink。本文将对这三个大数据处理框架进行比较&#xff0c;以及在不同场景下的选择考虑。…

测绘局内外网文件导入导出,怎样才能效率安全两手抓?

测绘局负责进行各种基础测绘工作&#xff0c;如地形测量、地籍测绘、海洋测绘等&#xff0c;获取并更新国家基础地理信息数据。这些数据是国民经济建设、城市规划、资源调查、环境保护等各个领域的重要基础资料。对于维护国家地理信息安全、促进国民经济和社会发展具有重要意义…

工业边缘计算网关

1 介绍 HINETG系列边缘计算网关&#xff08;Linux操作系统&#xff09;&#xff0c;是华辰智通的—款面向工业现场设备接入、数据采集、设备监控的工业级边缘计算网关。采用ARM Cortex-A7 800MHz高性能CPU,拥有以太网、串口、CAN口、IO口等丰富的接口&#xff0c;支持以太网、…

专业软件测试公司分享:安全测评对于软件产品的重要性

在互联网普及的今天&#xff0c;随着各类软件的大规模使用&#xff0c;安全问题也变得愈发突出。因此&#xff0c;对软件进行全面的安全测评&#xff0c;不仅可以有效保障用户的信息安全&#xff0c;还能提升软件产品的信任度和市场竞争力。 安全测评对于软件产品的重要性就如…

6.26.4 基于视觉变换的乳房x光片分类迁移学习

乳房x线摄影(MG)在乳腺癌的早期发现中起着重要作用。MG可以在早期发现乳腺癌&#xff0c;即使是不能感觉到肿块的小肿瘤。然而&#xff0c;由于mg的复杂性和放射科医生进行的大量检查&#xff0c;可能会出现误诊。为了给放射科医生提供一个公正的视角&#xff0c;应用图像处理方…

基于Vue 3.x与TypeScript的PPTIST本地部署与无公网IP远程演示文稿

文章目录 前言1. 本地安装PPTist2. PPTist 使用介绍3. 安装Cpolar内网穿透4. 配置公网地址5. 配置固定公网地址 前言 本文主要介绍如何在Windows系统环境本地部署开源在线演示文稿应用PPTist&#xff0c;并结合cpolar内网穿透工具实现随时随地远程访问与使用该项目。 PPTist …

step7:“模拟量界面”逻辑

文章目录 文章介绍效果图AnalogPage.qml结构图调用 SerialPortHandler.sendData(message); serialporthandler.cpp 文章介绍 之前的6步实现了案例MF的界面设计和串口界面的逻辑设计&#xff0c;本文将实现模拟量界面的逻辑设计 新增功能&#xff1a; 1&#xff09;弹出提示框 …

腾讯云点播VOD(sprintboot后端+vue前端)

1. 腾讯云点播 官网文档入口: 云点播简介_云点播购买指南_云点播操作指南-腾讯云 2. 业务需求 2.1.上传视频 2.2.浏览视频 2.3.删除视频 3. 腾讯云提供服务器上传和客户端上传。我使用springboot后端实现客户端上传视频。 3.1 后端要求 生成签名,前端拿着签名凭证,才能上…

四川赤橙宏海商务信息咨询有限公司抖音电商领航者

在数字化浪潮席卷全球的今天&#xff0c;电商行业无疑是其中最为活跃、最具潜力的领域之一。而在中国这片广袤的土地上&#xff0c;四川赤橙宏海商务信息咨询有限公司以其独特的视角和前瞻性的战略布局&#xff0c;成为了抖音电商服务领域的佼佼者。今天&#xff0c;就让我们一…

JavaWeb系列三: JavaScript学习 下

文章目录 js数组定义方式数组遍历 js函数函数入门函数使用方式使用方式一使用方式二 函数注意事项函数练习题 定义对象使用object定义使用{}定义 事件onload事件onclick事件失去焦点事件内容发生改变事件表单提交事件静态注册动态注册表单作业 dom对象文档对象模型document对象…

大数据智能风控:模型、平台与业务实践

人行印发的《金融科技&#xff08;FinTech&#xff09;发展规划&#xff08;2022一2025年&#xff09;》明确指出金融科技成为防范化解金融风险的利器&#xff0c;运用大数据、人工智能等技术建立金融风控模型&#xff0c;有效甄别高风险交易&#xff0c;智能感知异常交易&…

Linux双网卡默认路由的metric设置不正确,导致SSH连接失败问题定位

测试环境 VMware虚拟机 RockyLinux 9 x86_64 双网卡&#xff1a;eth0(访问外网): 10.206.216.92/24; eth1(访问内网) 192.168.1.4/24 问题描述 虚拟机重启后&#xff0c;SSH连接失败&#xff0c;提示"Connection time out"&#xff0c;重启之前SSH连接还是正常的…

Android集成高德地图SDK(2)

1.解压下载的压缩包&#xff0c;找到AMap_Android_SDK_All\AMap3DMap_DemoDocs\AMap_Android_API_3DMap_Demo\AMap3DDemo\app\libs&#xff0c;复制libs里的所有文件&#xff0c;将其粘贴到Android工程的libs目录下&#xff0c;如图所示。 2.打开app下的build.gradle&#xff0…

郭子威:未来香港楼市多方拉动稳健前行

今年2月&#xff0c;香港取消了实行14年的楼市“辣招”。“撤辣”之后&#xff0c;香港楼市迎来迅速反弹&#xff0c;3月一手房成交量环比涨逾10倍。 香港“撤辣”的背景是什么&#xff1f;撤辣之后对楼市的长远影响有哪些&#xff1f;未来香港楼市的表现将会如何&#xff1f; …

vite-plugin-mars3d插件最近版本打包问题

最新vite和最新mars3d不能打包会出现报错&#xff0c;一般是版本没有匹配&#xff0c;或者是相关的配置文件没有对&#xff0c; 参考我们开源仓库&#xff0c;修改相关的配置文件&#xff0c; 下载基础项目git clone mars3d-vue-project: 在Vue 3.x技术栈下的Mars3D平台 基础项…

【Redis】

Redis 常见面试题 认识 Redis 什么是 Redis&#xff1f; 我们直接看 Redis 官方是怎么介绍自己的。 Redis 官方的介绍原版是英文的&#xff0c;我翻译成了中文后截图的&#xff0c;所以有些文字读起来会比较拗口&#xff0c;没关系&#xff0c;我会把里面比较重要的特性抽出来…

AI时代的量化金融:ChatGPT在交易中的应用与前景

文章目录 &#x1f4d1;前言一、智能量化&#xff1a;开启金融新世界二、作者简介三、本书特色四、适读人群 在数字化、智能化的时代浪潮中&#xff0c;金融领域正经历着一场前所未有的变革。传统的金融分析方法逐渐被高效、精准的量化金融与算法交易所替代&#xff0c;而人工智…