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

news2024/11/23 19:49:57
一、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>,就说明这是一个抽象类,具体的创建实例的过程在其子类中。

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

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

相关文章

敏源-数字高精度温度探头可替代传统PT100/1000

传统模拟温度探头成本高、功耗高、数据采集不方便&#xff0c;而由工采网代理的敏源0.1℃数字温度探头&#xff0c;可替代传统的PT100/1000或升级热敏电阻探头&#xff1b;可应用于冷链、仓储、医疗、工业等低温/室温/高温高精度温度采集场景。 PT100温度传感器需要复杂的采集电…

BMS绝缘检测方案

目前已有绝缘检测方案大都类似&#xff0c;我想分享一下&#xff0c;同时也想提出一个问题&#xff1a;在总压1500V的时候&#xff0c;检测100K以下的阻值有什么很好的方案吗&#xff1f;希望有懂行的人能给予帮助&#xff0c;万分感谢&#xff01;&#xff01;&#xff01; 我…

电路与数字逻辑期末复习重点整理!!

1.带无关项的卡诺图 2.置数法设计N进制电路 计数器&#xff1a;具有记忆输入脉冲个数功能的电路称为计数器。 按照各个触发器状态更新情况的不同可分为&#xff1a; 同步计数器&#xff1a;各触发器受同一时钟脉冲─输入计数脉冲控制&#xff0c;同步更新状态。异步计数器&a…

AI大模型安全挑战和安全要求解读

引言 随着人工智能技术的飞速发展&#xff0c;大模型技术以其卓越的性能和广泛的应用前景&#xff0c;正在重塑人工智能领域的新格局。然而&#xff0c;任何技术都有两面性&#xff0c;大模型在带来前所未有便利的同时&#xff0c;也引发了深刻的安全和伦理挑战。 大模型&…

PointMamba: A Simple State Space Model for Point Cloud Analysis

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

通过验证邮箱进行注册信息确认

应用在进行注册时&#xff0c;避免恶意攻击和垃圾注册&#xff0c;可以通过验证注册者身份后才能够提交。一般可以使用验证手机短信或者验证邮箱&#xff0c;验证短信会有专门的第三方服务&#xff0c;可以进行付费购买。验证邮箱的正确与否&#xff0c;可以通过以下2种方式进行…

关于组织赴俄罗斯(莫斯科)第 28 届国际汽车零部件、汽车维修设备和商品展览会商务考察的通知

关于组织赴俄罗斯&#xff08;莫斯科&#xff09; 第 28 届国际汽车零部件、汽车维修设备和商品展览会商务考察的通知 展会名称&#xff1a;俄罗斯&#xff08;莫斯科&#xff09;第 28 届国际汽车零部件、汽车零部件、汽车维修设备和商品展览会 时间&#xff1a;2024 年 8 月…

【异常总结】SeaTunnel集群脑裂配置优化方法

集群配置 项目描述数量3台规格阿里云ECS 16C64GSlot模式静态50个ST内存配置-Xms32g -Xmx32g -XX:MaxMetaspaceSize8g 异常问题 4月份以来&#xff0c;出现了3次集群脑裂现象&#xff0c;均为某节点脑裂/自动关闭。 核心日志如下&#xff1a; Master节点 出现Hazelcast监控…

学会python——在excel中写入数据(python实例十三)

目录 1.认识Python 2.环境与工具 2.1 python环境 2.2 Visual Studio Code编译 3 .想Excel中写入数据 3.1 代码构思 3.2 代码实例 3.3 运行结果 4.总结 1.认识Python Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的…

[JS]DOM元素

介绍 DOM(Document Object Model---文档对象模型) 是浏览器提供的一套专门用来操作网页内容的API DOM树 把HTML文档以树状结构直观的表现出来, 称为文档数或者DOM树, DOM树直观的展示了标签与标签的关系 DOM对象 浏览器根据html标签生成的JS对象称为DOM对象 document对象 …

Java 树形结构数据如何高效返回给前端进行展示?

在开发过程中我们总是遇到一些具有层次结构的数据&#xff0c;这些数据在前端也总是需要以树形结构进行显示&#xff0c;那么后端接口如何高效的去将这些数据封装成树形结构呢&#xff1f;下面来进行解析讲解。 最终实现的一个结果图 设计返回的实体VO import com.fasterxm…

PTA—C语言期末复习(选择题)

1. 按照标识符的要求&#xff0c;&#xff08;A&#xff09;不能组成标识符。 A.连接符 B.下划线 C.大小写字母 D.数字字符 在大多数编程语言中&#xff0c;标识符通常由字母&#xff08;包括大写和小写&#xff09;、数字和下划线组成&#xff0c;但不能以数字开头&#xff0c…

聚类算法(3)---K-means 算法

本篇文章是博主在人工智能等领域学习时&#xff0c;用于个人学习、研究或者欣赏使用&#xff0c;并基于博主对人工智能等领域的一些理解而记录的学习摘录和笔记&#xff0c;若有不当和侵权之处&#xff0c;指出后将会立即改正&#xff0c;还望谅解。文章分类在AI学习笔记&#…

firewalld(1)基本原理

简介 Firewalld是一种提供了支持网络/防火墙区域(zone)定义网络链接以及接口安全等级的动态防火墙管理工具,它自身并不具备防火墙的功能,而是和iptables一样需要通过内核的netfilter来实现,数据包过滤机制(Netfilter)有两个软件:firewalld与iptables。也就是说firewalld…

高德地图获取key值步骤

1、创建新应用 进入控制台&#xff08;https://lbs.amap.com/dev/&#xff09;&#xff0c;创建一个新应用。 如果您之前已经创建过应用&#xff0c;可直接跳过这个步骤。 2、添加新Key 在创建的应用上分别填写key名称、选择服务平台、SHA1、以及PackageName SHA1:是在安卓…

java实现双线性映射

1.目录结构 2.导包 将jpbc-api-2.0.0.jar和jpbc-plaf-2.0.0.jar导入到java项目中 网盘链接&#xff1a;链接: https://pan.baidu.com/s/1lFLXQj8v_EhL9KZYaaRv1w?pwde8db 提取码: e8db 3.编写代码 a.properties type a q 878071079966331252243778198475404981580688319941…

MSA 助力实验室测量更稳定、更准确

在汽车制造、石油化工、电子制造等行业,产品的质量和性能需要通过准确的测量来保证。但是由于测量设备的误差、操作人员的主观影响以及环境条件的干扰等因素会导致测量系统出现各种问题,且这些问题会导致测量结果不准确,从而影响产品质量。 随着工业信息化的迅速发展, 各行业对…

串口通信中字符和16进制显示的区别分析,串口发送数据

分析的原因 在对串口传送数值时&#xff0c;不想再进行一步字符转化&#xff0c;想要直接传送数值。但查看时就需要以16进制的数值形式查看数据&#xff0c;否则将不能看到正确的数据显示 下图是对串口寄存器发送一个16bit位的数据 void uart0Senduint16(UINT16 dat){SBUFdat…

使用Python Selenium,动态网页不再是难题!

目录 1、直接执行JS代码 🌐 1.1 execute_script基础用法 1.2 带参数执行JS函数 1.3 获取执行结果 2、使用execute_async_script异步执行 🔄 2.1 适用场景分析 2.2 实现异步操作示例 2.3 错误处理与调试技巧 3、JS与页面元素交互 👤 3.1 修改DOM属性 3.2 触发事…

KVM性能优化之磁盘IO优化

方法一&#xff1a;通过直接在XML里定义&#xff1a; 1.磁盘类型选择 <target devsda busscsi/> PS:virti0模式读写低于sata和SCSI模式&#xff0c;SCSI模式最高&#xff0c;大数据集建议使用SCSI 2.缓存模式选择 <driver nameqemu typeqcow2 cachenone/> 加上…