Java——Spring中BeanFactory与FactoryBean

news2024/11/28 19:58:30

在Spring框架中,BeanFactoryFactoryBean 是两个不同但相关的概念。它们各自有不同的用途和工作方式。

BeanFactory

BeanFactory 是Spring IoC容器的核心接口,它提供了配置框架和基本功能来管理任何类型的对象。BeanFactory 本身是一个工厂,用于创建和管理Spring中的Bean。它负责读取Bean定义,并根据这些定义实例化、配置以及管理Bean的生命周期。

  • 主要职责:创建和管理Bean。
  • 实现类:常见的实现类有 DefaultListableBeanFactory 和 XmlBeanFactory(已废弃)等。
  • 使用场景:当你需要一个轻量级的IoC容器时,可以使用 BeanFactory。不过,在大多数情况下,推荐使用更强大的 ApplicationContext,它是 BeanFactory 的子接口,提供了更多的企业级功能。

FactoryBean

FactoryBean 是Spring提供的一个接口,用于自定义复杂的对象创建过程。如果一个Bean实现了 FactoryBean 接口,那么Spring会调用它的 getObject() 方法来获取最终要注入到其他Bean中的对象。这使得你可以控制Bean的创建逻辑,例如,你可以返回一个代理对象或者进行一些复杂的初始化操作。

  • 主要职责:自定义复杂对象的创建逻辑。
  • 方法
    • T getObject():返回由这个工厂Bean创建的对象。
    • Class<?> getObjectType():返回由 getObject() 返回的对象类型。
    • boolean isSingleton():指定由 getObject() 返回的对象是否为单例。
  • 使用场景:当你需要对Bean的创建过程有更多的控制时,可以实现 FactoryBean 接口。例如,创建JNDI数据源、代理对象等。

区别总结

  • 目的

    • BeanFactory 是Spring的IoC容器,用来管理和创建所有的Bean。
    • FactoryBean 是一个特殊的Bean,它自己定义了如何创建和管理一个具体的Bean。
  • 作用

    • BeanFactory 用于创建和管理所有的Bean,包括那些普通的Bean和实现了 FactoryBean 的Bean。
    • FactoryBean 用于创建特定的Bean,通常用于复杂的对象创建逻辑。
  • 获取对象的方式

    • 从 BeanFactory 获取Bean时,直接返回的是Bean实例。
    • 从 BeanFactory 获取实现了 FactoryBean 的Bean时,返回的是 FactoryBean 的 getObject() 方法的结果,而不是 FactoryBean 实例本身。如果需要获取 FactoryBean 实例,可以在Bean ID前加上 & 符号,如 &myFactoryBean

通过理解这两个概念的区别,你可以更好地利用Spring框架的功能来满足应用程序的需求。如果你的应用中有复杂的对象创建需求,考虑使用 FactoryBean;而对于一般的依赖注入和Bean管理,BeanFactoryApplicationContext 就足够了。

示例代码

为了更好地理解 BeanFactoryFactoryBean 的区别,我们可以分别通过代码示例来说明它们的使用方式。

BeanFactory 示例

首先,我们创建一个简单的Spring配置类和一个普通的Bean。然后,我们将使用 BeanFactory 来获取这个Bean。

定义一个简单的Bean

public class SimpleBean {
    public void sayHello() {
        System.out.println("Hello, I am a simple bean!");
    }
}

创建Spring配置类

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public SimpleBean simpleBean() {
        return new SimpleBean();
    }
}

使用BeanFactory获取Bean

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        // 创建BeanFactory
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        // 使用AnnotationConfigApplicationContext加载配置类
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        context.refresh();

        // 从BeanFactory中获取Bean
        SimpleBean simpleBean = (SimpleBean) context.getBean("simpleBean");
        simpleBean.sayHello();

        // 关闭上下文
        context.close();
    }
}

在这个例子中,我们使用了 DefaultListableBeanFactory 作为 BeanFactory 实现,并通过 AnnotationConfigApplicationContext 加载配置类来管理Bean。然后,我们从 BeanFactory 中获取 SimpleBean 并调用其方法。

FactoryBean 示例

接下来,我们创建一个实现了 FactoryBean 接口的类,该类将返回一个代理对象。

定义一个接口

public interface MyService {
    void doSomething();
}

实现接口

public class MyServiceImpl implements MyService {
    @Override
    public void doSomething() {
        System.out.println("Doing something in MyServiceImpl");
    }
}

创建一个FactoryBean

import org.springframework.beans.factory.FactoryBean;

public class MyServiceFactoryBean implements FactoryBean<MyService> {

    private final MyService myService;

    public MyServiceFactoryBean(MyService myService) {
        this.myService = myService;
    }

    @Override
    public MyService getObject() throws Exception {
        return (MyService) Proxy.newProxyInstance(
            getClass().getClassLoader(),
            new Class<?>[]{MyService.class},
            (proxy, method, args) -> {
                System.out.println("Before method call");
                Object result = method.invoke(myService, args);
                System.out.println("After method call");
                return result;
            });
    }

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

    @Override
    public boolean isSingleton() {
        return true;
    }
}

创建Spring配置类

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public MyServiceImpl myServiceImpl() {
        return new MyServiceImpl();
    }

    @Bean
    public MyServiceFactoryBean myServiceFactoryBean(MyServiceImpl myServiceImpl) {
        return new MyServiceFactoryBean(myServiceImpl);
    }
}

使用ApplicationContext获取FactoryBean创建的对象


import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainApp {
    public static void main(String[] args) throws Exception {
        // 创建ApplicationContext
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        // 从ApplicationContext中获取FactoryBean创建的对象
        MyService myService = context.getBean(MyServiceImpl.class);
        myService.doSomething();

        // 获取FactoryBean本身
        MyServiceFactoryBean factoryBean = (MyServiceFactoryBean) context.getBean("&myServiceFactoryBean");
        System.out.println("FactoryBean: " + factoryBean);

        //从FactoryBean中获取对象(已经实现动态代理)
        myService = factoryBean.getObject();
        myService.doSomething();

        // 关闭上下文
        ((AnnotationConfigApplicationContext) context).close();
    }
}

在这个例子中,MyServiceFactoryBean 实现了 FactoryBean 接口,并且返回了一个代理对象。当我们从 ApplicationContext 中获取 MyService 类型的Bean时,实际上得到的是由 MyServiceFactoryBean 创建的代理对象。如果需要获取 FactoryBean 本身,可以通过在Bean ID前加上 & 符号来实现。

通过这两个示例,你可以看到 BeanFactoryFactoryBean 在Spring中的不同用途和工作方式。BeanFactory 是用于管理和创建所有Bean的基础容器,而 FactoryBean 则提供了自定义复杂对象创建逻辑的能力。

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

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

相关文章

Flink--API 之 Source 使用解析

目录 一、Flink Data Sources 分类概览 &#xff08;一&#xff09;预定义 Source &#xff08;二&#xff09;自定义 Source 二、代码实战演示 &#xff08;一&#xff09;预定义 Source 示例 基于本地集合 基于本地文件 基于网络套接字&#xff08;socketTextStream&…

typescript基础入门

在官网的页页https://www.typescriptlang.org/可以调试。 &#xff03;类型推断 let str: string abclet str1: string str1a&#xff03;数组及类型断言let numArr [1, 2, 3]const result numArr.find(item > item >2) as numberresult * 5&#xff03;基础类型和…

SenseVoice 音频转文字情绪识别 - python 实现

具体代码实现如下&#xff1a; from funasr import AutoModel from funasr.utils.postprocess_utils import rich_transcription_postprocesspath_audio "emo/happy.mp3"# 音频文件 # 加载模型 model_dir "iic/SenseVoiceSmall" model AutoModel(model…

Java学习笔记--继承方法的重写介绍,重写方法的注意事项,方法重写的使用场景,super和this

目录 一&#xff0c;方法的重写 二&#xff0c;重写方法的注意事项 三&#xff0c;方法重写的使用场景 四&#xff0c;super和this 1.继承中构造方法的特点 2.super和this的具体使用 super的具体使用 this的具体使用 一&#xff0c;方法的重写 1.概述:子类中有一个和父类…

深入浅出摸透AIGC文生图产品SD(Stable Diffusion)

hihi,朋友们,时隔半年(24年11月),终于能腾出时间唠一唠SD了🤣,真怕再不唠一唠,就轮不到SD了,技术更新换代是在是太快! 朋友们,最近(24年2月)是真的没时间整理笔记,每天都在疯狂的学习Stable Diffusion和WebUI & ComfyUI,工作实在有点忙,实践期间在飞书上…

OSI七层模型和TCP/IP五层模型详细介绍

这里写目录标题 一.OSI含义二.OSI七层模型1.应用层2.表示层3.会话层4.传输层5.网络层6.数据链路层7.物理层 TCP/IP五层协议1.应用层2.运输层运行在TCP上的协议运行在UDP上的协议 3.网络层IP协议配套使用的协议 4.数据链路层 四.网络协议分层的好处 一.OSI含义 OSI即是开放式通…

360推出全新的生成式 AI 搜索产品:纳米搜索,要重塑搜索产品

【大力财经】直击互联网最前线&#xff1a;360 集团在 2024 年 11 月 27 日开发布会&#xff0c;重磅推出了一款全新的生成式 AI 搜索产品——纳米搜索&#xff0c;并且已经上架到苹果 App Store 以及应用宝等安卓应用商店&#xff0c;直接与百度、阿里夸克、秘塔 AI、Perplexi…

【超全】目标检测模型分类对比与综述:单阶段、双阶段、有无锚点、DETR、旋转框

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

c#:winform引入bartender

1、vs新建项目 ①选择Windows窗体应用&#xff08;.NET Framework&#xff09; 2、将bartender引入vs中 ①找到bartender的安装目录&#xff0c;复制Seagull.BarTender.Print.dll文件 ②粘贴到项目->bin->Debug文件&#xff0c;并可创建Model文件夹&#xff1a;为了存放…

vue 实现关键字高亮效果

vue 实现关键字高亮效果 这是啥子意思呢&#xff0c;就是类似于百度搜索&#xff0c;根据关键词搜索结果&#xff0c;搜索结果中&#xff0c;与关键词相同的字显示红色&#xff0c;仅此而已&#xff0c;没有什么大的功能。简单写一下demo。 环境 我使用的是 vue3 ts 的语法来…

初始Python篇(7)—— 正则表达式

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a; Python 目录 正则表达式的概念 正则表达式的组成 元字符 限定符 其他字符 正则表达式的使用 正则表达式的常见操作方法 match方法的…

[DL]深度学习_扩散模型正弦时间编码

1 扩散模型时间步嵌入 1.1 时间步正弦编码 在扩散模型按时间步 t 进行加噪去噪过程时&#xff0c;需要包括反映噪声水平的时间步长 t 作为噪声预测器的额外输入。但是最初与图像配套的时间步 t 是数字&#xff0c;需要将代表时间步 t 的数字编码为向量嵌入。嵌入时间向量的宽…

【Linux】网络基本配置命令

一、使用网络配置命令 1.常用网络配置文件 1.1. /etc/hosts “/etc/hosts”文件保存着IP地址和主机名或域名的静态映射关系。当用户使用一个主机名或域名时&#xff0c;系统会在该文件中查找与它对应的IP地址。 [rootlocalhost ~]# cat /etc/hosts 127.0.0.1 localhost l…

如何搭建一个小程序:从零开始的详细指南

在当今数字化时代&#xff0c;小程序以其轻便、无需下载安装即可使用的特点&#xff0c;成为了连接用户与服务的重要桥梁。无论是零售、餐饮、教育还是娱乐行业&#xff0c;小程序都展现了巨大的潜力。如果你正考虑搭建一个小程序&#xff0c;本文将为你提供一个从零开始的详细…

学习threejs,使用设置lightMap光照贴图创建阴影效果

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.MeshLambertMaterial…

【前端】JavaScript中的柯里化(Currying)详解及实现

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: 前端 文章目录 &#x1f4af;前言&#x1f4af;什么是柯里化&#xff1f;&#x1f4af;柯里化的特点&#x1f4af;柯里化的简单示例&#x1f4af;通用的柯里化实现&#x1f4af;柯里化让代码更易读的原因&#x1f4af…

springboot 整合 rabbitMQ (延迟队列)

前言&#xff1a; 延迟队列是一个内部有序的数据结构&#xff0c;其主要功能体现在其延时特性上。这种队列存储的元素都设定了特定的处理时间&#xff0c;意味着它们需要在规定的时间点或者延迟之后才能被取出并进行相应的处理。简而言之&#xff0c;延时队列被设计用于存放那…

Java代码操作Zookeeper(使用 Apache Curator 库)

1. Zookeeper原生客户端库存在的缺点 复杂性高&#xff1a;原生客户端库提供了底层的 API&#xff0c;需要开发者手动处理很多细节&#xff0c;如连接管理、会话管理、异常处理等。这增加了开发的复杂性&#xff0c;容易出错。连接管理繁琐&#xff1a;使用原生客户端库时&…

Django实现智能问答助手-基础配置

设置 Django 项目、创建应用、定义模型和视图、实现问答逻辑&#xff0c;并设计用户界面。下面是一步一步的简要说明&#xff1a; 目录&#xff1a; QnAAssistant/ # 项目目录 │ ├── QnAAssistant/ # 项目文件夹 │ ├── init.py # 空文件 │ ├── settings.py # 项目配…

【ESP32CAM+Android+C#上位机】ESP32-CAM在STA或AP模式下基于UDP与手机APP或C#上位机进行视频流/图像传输

前言: 本项目实现ESP32-CAM在STA或AP模式下基于UDP与手机APP或C#上位机进行视频流/图像传输。本项目包含有ESP32源码(arduino)、Android手机APP源码以及C#上位机源码,本文对其工程项目的配置使用进行讲解。实战开发,亲测无误。 AP模式,就是ESP32发出一个WIFI/热点提供给电…