8、如何使用FactoryBean向Spring容器中注册bean?

news2025/1/6 20:43:50

在这里插入图片描述

📫作者简介:zhz小白
公众号:小白的Java进阶之路
专业技能:
1、Java基础,并精通多线程的开发,熟悉JVM原理
2、熟悉Java基础,并精通多线程的开发,熟悉JVM原理,具备⼀定的线上调优经验
3、熟悉MySQL数据库调优,索引原理等,⽇志原理等,并且有出过⼀篇专栏
4、了解计算机⽹络,对TCP协议,滑动窗⼝原理等有⼀定了解
5、熟悉Spring,Spring MVC,Mybatis,阅读过部分Spring源码
6、熟悉SpringCloud Alibaba体系,阅读过Nacos,Sentinel,Seata,Dubbo,Feign,Gateway核⼼源码与设计,⼆次开发能⼒
7、熟悉消息队列(Kafka,RocketMQ)的原理与设计
8、熟悉分库分表ShardingSphere,具有真实⽣产的数据迁移经验
9、熟悉分布式缓存中间件Redis,对其的核⼼数据结构,部署架构,⾼并发问题解决⽅案有⼀定的积累
10、熟悉常⽤设计模式,并运⽤于实践⼯作中
11、了解ElasticSearch,对其核⼼的原理有⼀定的了解
12、了解K8s,Jekins,GitLab
13、了解VUE,GO
14、⽬前有正在利⽤闲暇时间做互游游戏,开发、运维、运营、推销等

本人著作git项目:https://gitee.com/zhouzhz/star-jersey-platform,有兴趣的可以私聊博主一起编写,或者给颗star
领域:对支付(FMS,FUND,PAY),订单(OMS),出行行业等有相关的开发领域
🔥如果此文还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主~

文章目录

  • 1、定义
  • 2、源码
    • 2.1、分析
      • 2.1.1、T getObject()
      • 2.1.2、Class<?> getObjectType()
      • 2.1.3、boolean isSingleton()
    • 2.2、案例
      • 2.2.1、手写FactoryBean的实现类
      • 2.2.2、在MainConfig注册TestFactoryBean
      • 2.2.3、运行结果
      • 2.2.4、疑问:怎么获取FactoryBean对象本身?加&
      • 2.4.5、为什么加了&之后就能获取FactoryBean对象实例呢?

1、定义

  • 一般情况下,Spring是通过反射机制利用bean的class属性指定实现类来实例化bean的。在某些情况下,实例化bean过程比较复杂,如果按照传统的方式,那么则需要在标签中提供大量的配置信息,配置方式的灵活性是受限的,这时采用编码的方式可以得到一个更加简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化bean的逻辑。
  • 简单理解为我们可以自己创造Bean,不需要通过BeanPostProcessor来干涉Spring创建bean的过程(factorybean创建的bean只会经过初始化后,其他Spring的生命周期不会经过)

2、源码

/*
 * Copyright 2002-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory;

import org.springframework.lang.Nullable;

/**
 * Interface to be implemented by objects used within a {@link BeanFactory} which
 * are themselves factories for individual objects. If a bean implements this
 * interface, it is used as a factory for an object to expose, not directly as a
 * bean instance that will be exposed itself.
 *
 * <p><b>NB: A bean that implements this interface cannot be used as a normal bean.</b>
 * A FactoryBean is defined in a bean style, but the object exposed for bean
 * references ({@link #getObject()}) is always the object that it creates.
 *
 * <p>FactoryBeans can support singletons and prototypes, and can either create
 * objects lazily on demand or eagerly on startup. The {@link SmartFactoryBean}
 * interface allows for exposing more fine-grained behavioral metadata.
 *
 * <p>This interface is heavily used within the framework itself, for example for
 * the AOP {@link org.springframework.aop.framework.ProxyFactoryBean} or the
 * {@link org.springframework.jndi.JndiObjectFactoryBean}. It can be used for
 * custom components as well; however, this is only common for infrastructure code.
 *
 * <p><b>{@code FactoryBean} is a programmatic contract. Implementations are not
 * supposed to rely on annotation-driven injection or other reflective facilities.</b>
 * {@link #getObjectType()} {@link #getObject()} invocations may arrive early in the
 * bootstrap process, even ahead of any post-processor setup. If you need access to
 * other beans, implement {@link BeanFactoryAware} and obtain them programmatically.
 *
 * <p><b>The container is only responsible for managing the lifecycle of the FactoryBean
 * instance, not the lifecycle of the objects created by the FactoryBean.</b> Therefore,
 * a destroy method on an exposed bean object (such as {@link java.io.Closeable#close()})
 * will <i>not</i> be called automatically. Instead, a FactoryBean should implement
 * {@link DisposableBean} and delegate any such close call to the underlying object.
 *
 * <p>Finally, FactoryBean objects participate in the containing BeanFactory's
 * synchronization of bean creation. There is usually no need for internal
 * synchronization other than for purposes of lazy initialization within the
 * FactoryBean itself (or the like).
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 08.03.2003
 * @param <T> the bean type
 * @see org.springframework.beans.factory.BeanFactory
 * @see org.springframework.aop.framework.ProxyFactoryBean
 * @see org.springframework.jndi.JndiObjectFactoryBean
 */
public interface FactoryBean<T> {

	/**
	 * The name of an attribute that can be
	 * {@link org.springframework.core.AttributeAccessor#setAttribute set} on a
	 * {@link org.springframework.beans.factory.config.BeanDefinition} so that
	 * factory beans can signal their object type when it can't be deduced from
	 * the factory bean class.
	 * @since 5.2
	 */
	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";


	/**
	 * Return an instance (possibly shared or independent) of the object
	 * managed by this factory.
	 * <p>As with a {@link BeanFactory}, this allows support for both the
	 * Singleton and Prototype design pattern.
	 * <p>If this FactoryBean is not fully initialized yet at the time of
	 * the call (for example because it is involved in a circular reference),
	 * throw a corresponding {@link FactoryBeanNotInitializedException}.
	 * <p>As of Spring 2.0, FactoryBeans are allowed to return {@code null}
	 * objects. The factory will consider this as normal value to be used; it
	 * will not throw a FactoryBeanNotInitializedException in this case anymore.
	 * FactoryBean implementations are encouraged to throw
	 * FactoryBeanNotInitializedException themselves now, as appropriate.
	 * @return an instance of the bean (can be {@code null})
	 * @throws Exception in case of creation errors
	 * @see FactoryBeanNotInitializedException
	 */
	@Nullable
	T getObject() throws Exception;

	/**
	 * Return the type of object that this FactoryBean creates,
	 * or {@code null} if not known in advance.
	 * <p>This allows one to check for specific types of beans without
	 * instantiating objects, for example on autowiring.
	 * <p>In the case of implementations that are creating a singleton object,
	 * this method should try to avoid singleton creation as far as possible;
	 * it should rather estimate the type in advance.
	 * For prototypes, returning a meaningful type here is advisable too.
	 * <p>This method can be called <i>before</i> this FactoryBean has
	 * been fully initialized. It must not rely on state created during
	 * initialization; of course, it can still use such state if available.
	 * <p><b>NOTE:</b> Autowiring will simply ignore FactoryBeans that return
	 * {@code null} here. Therefore, it is highly recommended to implement
	 * this method properly, using the current state of the FactoryBean.
	 * @return the type of object that this FactoryBean creates,
	 * or {@code null} if not known at the time of the call
	 * @see ListableBeanFactory#getBeansOfType
	 */
	@Nullable
	Class<?> getObjectType();

	/**
	 * Is the object managed by this factory a singleton? That is,
	 * will {@link #getObject()} always return the same object
	 * (a reference that can be cached)?
	 * <p><b>NOTE:</b> If a FactoryBean indicates to hold a singleton object,
	 * the object returned from {@code getObject()} might get cached
	 * by the owning BeanFactory. Hence, do not return {@code true}
	 * unless the FactoryBean always exposes the same reference.
	 * <p>The singleton status of the FactoryBean itself will generally
	 * be provided by the owning BeanFactory; usually, it has to be
	 * defined as singleton there.
	 * <p><b>NOTE:</b> This method returning {@code false} does not
	 * necessarily indicate that returned objects are independent instances.
	 * An implementation of the extended {@link SmartFactoryBean} interface
	 * may explicitly indicate independent instances through its
	 * {@link SmartFactoryBean#isPrototype()} method. Plain {@link FactoryBean}
	 * implementations which do not implement this extended interface are
	 * simply assumed to always return independent instances if the
	 * {@code isSingleton()} implementation returns {@code false}.
	 * <p>The default implementation returns {@code true}, since a
	 * {@code FactoryBean} typically manages a singleton instance.
	 * @return whether the exposed object is a singleton
	 * @see #getObject()
	 * @see SmartFactoryBean#isPrototype()
	 */
	default boolean isSingleton() {
		return true;
	}

}

当配置文件中标签的class属性配置的实现类是FactoryBean时,通过 getBean()方法返回的不是FactoryBean本身,而是FactoryBean#getObject()方法所返回的对象,相当于FactoryBean#getObject()代理了getBean()方法。

2.1、分析

2.1.1、T getObject()

  • 返回由FactoryBean创建的bean实例,如果isSingleton()返回true,那么该实例会放到Spring容器中单实例缓存池中

2.1.2、Class<?> getObjectType()

  • 返回FactoryBean创建的bean实例的类型

2.1.3、boolean isSingleton()

  • 返回由FactoryBean创建的bean实例的作用域是singleton还是prototype

2.2、案例

2.2.1、手写FactoryBean的实现类

我们写一个TestFactoryBean类,它实现了FactoryBean接口,代码如下:

package com.zhz.factorybean;

import com.zhz.bean.UserService;
import org.springframework.beans.factory.FactoryBean;

/**
 * 创建一个Spring定义的FactoryBean
 * T(泛型):指定我们要创建什么类型的对象
 * @author zhouhengzhe
 * @date 2022/11/18
 */
public class TestFactoryBean implements FactoryBean<UserService> {

    /**
    * 返回一个UserService对象,这个对象会添加到容器中
    */
    @Override
    public UserService getObject() throws Exception {
        return new UserService();
    }

    @Override
    public Class<?> getObjectType() {
        // 返回这个对象的类型
        return UserService.class;
    }

     /**
     * 是单例吗?
     * 如果返回true,那么代表这个bean是单实例,在容器中只会保存一份;
     * 如果返回false,那么代表这个bean是多实例,每次获取都会创建一个新的bean
     *
     * @return
     */
    @Override
    public boolean isSingleton() {
        return true;
    }
}

其中里面的UserService代码如下:

package com.zhz.bean;

/**
 * @author zhouhengzhe
 * @date 2022/11/18
 */
public class UserService {
}

2.2.2、在MainConfig注册TestFactoryBean

然后我们在MainConfig中注册TestFactoryBean,此处我们用的是@Bean向Spring容器注册对象,代码如下


@Bean
public TestFactoryBean testFactoryBean(){
    return new TestFactoryBean();
}

然后我们运行一下test方法,代码如下:

   @Test
    public void test3(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
        Object colorFactoryBean = applicationContext.getBean("testFactoryBean");
        System.out.println("bean的类型为:"+colorFactoryBean);
    }

2.2.3、运行结果

我们看一下运行结果:
在这里插入图片描述

总结:

  • 我们在实际中虽然使用的是@Bean注解向容器中注册的是TestFactoryBean对象,但是确是调用的getObject()方法,对象类型是getObject的返回值

2.2.4、疑问:怎么获取FactoryBean对象本身?加&

我么只需要在获取Bean的时候,加上&符号,那么他就会获取FactoryBean本身了,比如**&testFactoryBean**

 @Test
    public void test3(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
        Object colorFactoryBean = applicationContext.getBean("&testFactoryBean");
        System.out.println("bean的类型为:"+colorFactoryBean);
    }

运行结果
在这里插入图片描述

扩展:如果当前Bean不是FactoryBean的实现类,也加了&,那么会报错,具体样例如下:如下我们的person就是一个跟简单的Bean类

  @Test
    public void test3(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
        Object colorFactoryBean = applicationContext.getBean("&testFactoryBean");
        Object person = applicationContext.getBean("&person");
        System.out.println("bean的类型为:"+colorFactoryBean);
        System.out.println("bean的类型为:"+person);
    }

运行结果为:
在这里插入图片描述

2.4.5、为什么加了&之后就能获取FactoryBean对象实例呢?

我们看其BeanFactory接口,源码如下:
在这里插入图片描述

  • 在BeanFactory接口中定义了一个**&**前缀,只要我们使用bean的id来从Spring容器中获取bean时,Spring就会知道我们是在获取FactoryBean本身。

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

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

相关文章

openEuler快速入门-openEuler命令行基础操作

系列文章目录 第一章 openEuler快速入门(一)-openEuler操作系统介绍 文章目录系列文章目录前言一、shell是什么二、Linux命令行操作技巧三、基础命令3.1、Linux命令分类3.2、目录和文件3.2.1 相对路径和绝对路径3.2.2 处理目录的常用命令ls&#xff1a;cd&#xff1a;pwd&…

tkinter绘制组件(36)——树状图

tkinter绘制组件&#xff08;36&#xff09;——树状图引言布局函数结构内容数据格式整体框架绘制元素与重绘宽度标识元素展开与闭合完整函数代码效果测试代码最终效果github项目pip下载结语引言 TinUI的第38个元素控件&#xff0c;也是TinUI-4.0-添加的第一个组件&#xff0c…

Rsync下行同步+inotify实时同步介绍和部署

一、Rsync&#xff08;Remote Sync&#xff0c;远程同步&#xff09; 是一个开源的快速备份工具&#xff0c;可以在不同主机之间镜像同步整个目录树&#xff0c;支持增量备份&#xff0c;并保持链接和权限&#xff0c;且采用优化的同步算法&#xff0c;传输前执行压缩&#xf…

2022世界杯结果预测,简单AI模型最有效?附代码!

2022世界杯冠军是谁&#xff1f;本文将为你揭晓一个利用简单AI模型得到的靠谱预测。 许多人称足球为“不可预测的比赛”&#xff0c;因为一场足球比赛有不同的因素可以改变最终比分。 这是真的……在某种程度上。 北大出版社&#xff0c;人工智能原理与实践 人工智能和数据科…

面试官:什么是伪共享,如何避免?

本文已收录到 GitHub AndroidFamily&#xff0c;有 Android 进阶知识体系&#xff0c;欢迎 Star。技术和职场问题&#xff0c;请关注公众号 [彭旭锐] 加入 Android 交流群。 前言 大家好&#xff0c;我是小彭。 在前面的文章里&#xff0c;我们聊到了 CPU 的高速缓存机制。…

【electron】判断当前进程是否是开发环境的五种方案(获取一些资源的路径)

文章目录导读需求开发环境判断是否是开发环境方案一&#xff1a;location.protocol方案二&#xff1a;全局变量__static方案三&#xff1a;全局变量process.resourcesPath方案四&#xff1a;全局变量process.env.WEBPACK_DEV_SERVER方案五&#xff1a;app.isPackaged获取配置目…

OS-process

process 什么是进程 进程是被加载到内存中、正在运行的程序&#xff1b;多个进程可能对于同一个程序、一个正在运行的OS中会有多个进程 进程是程序的一次执行过程&#xff0c;是操作系统分配资源的基本单位 作业等同于进程 进程的布局&#xff1a; 每个进程都有一个不同的…

内网渗透中最常见的十种漏洞分析总结

【环境搭建资料、工具包、全套视频…等籽料】私信聆取 以下信息是根据2020年和2019年为全球各种中型组织和企业完成的60多个渗透测试报告汇总而来的&#xff0c;在跳转到列表之前&#xff0c;让我们简要介绍一下全面的测试方法。 一、测试方法 目的是使用白盒(灰盒)方法在现场…

spirngboot项目.mvn/wrapper/maven-wrapper.properties‘ does not exist.

rm -rf ~ 命令后&#xff0c;项目出现一些问题&#xff0c;如下 执行命令&#xff1a; ./mvnw clean package -am -pl bistoury-dist -P$PROFILR -Dmaven.test.skip -Denforcer.skiptrue 报异常&#xff1a; starting to build bistoury agent Exception in thread "ma…

[附源码]java毕业设计同德佳苑物业管理系统论文

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

SpringBoot数据层解决方案/ 内置持久化解决方案JdbcTemplate使用/内置数据库H2使用以及RedisNoSql使用

写在前面&#xff1a; 继续记录自己的SpringBoot学习之旅&#xff0c;这次是SpringBoot应用相关知识学习记录。若看不懂则建议先看前几篇博客&#xff0c;详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用&#xff01; 3.4 数据层解决方案 3.4.1 使用项目 新建空项目&a…

redis的事务

Redis的事务&#xff1a;一次事务操作&#xff0c;改成功的成功&#xff0c;该失败的失败。 提交事务 如果遇见错误 成功的成功&#xff0c;失败的失败&#xff0c;不会回滚 先开启事务&#xff0c;执行一些列的命令&#xff0c;但是命令不会立即执行&#xff0c;会被放在一…

web分享会

文章目录前言平台1. 在线练习平台2. 自己搭建靶场3. CTF真题平台分享前言 个人的学习过程仅供参考。 个人情况 我是大二进的工作室&#xff0c;算是比较晚的了&#xff0c;工作室的师兄人也很好&#xff0c;我有问题也会去找他们。我是一位女生&#xff0c;非常欢迎师妹们加入&…

从购买云服务器开始到成功部署网站并且可以正常外网访问整个体系流程(从0到1的过程)

准备工作&#xff1a; 购买云服务器(阿里云或腾讯云都行)&#xff0c;过程一样。购买域名&#xff0c;并做解析处理&#xff0c;通过域名访问网站(后面需要自行备案)。 云服务器一些基本配置处理&#xff1a; 用密码登录方式登录root用户到云服务器上 登录成功后&#xff0c…

MHDNet

发现一种性能更优的目标检测网络&#xff0c;不同的输入分辨率下&#xff0c;目标分布和检测头之间存在不同的匹配关系。基于这些有指导意义的发现&#xff0c;作者提出了一种基于检测头和目标分布之间匹配的轻量化交通目标检测网络&#xff0c;称为MHDNet。该模型在BDD100K数据…

【k8s】3、kubeadm安装k8s集群

文章目录一、环境部署1、关闭防火墙规则、关闭selinux、关闭swap交换分区2、修改主机名、DNS解析3、调整内核参数二、所有节点安装Docker三、安装k8s集群1、所有节点配置K8S源2、所有节点安装kubeadm、kubelet和kubectl3、部署K8S集群3.1 初始化操作&#xff08;master节点操作…

【虚幻引擎UE】UE4/UE5 环境构建插件推荐及使用介绍

一、Ultra Dynamic Sky&#xff08;天气插件&#xff09; 支持天气和昼夜变换&#xff0c;包含音效&#xff0c;可以预设也可以动态切换。内置照明解决方案&#xff0c;太阳、月亮和天空照明均与天空同步&#xff0c;并随时间变化。 天气包含&#xff1a;晴天、2D晴天、雨天、…

进程的通信 - 命名管道

命名管道概述 命名管道&#xff08;Named Pipes&#xff09;&#xff0c;顾名思义&#xff0c;一个有名字的管道。命名管道的名字主要是用于确保多个进程访问同一个对象。命名管道不仅可以在同一台计算机之间传输数据&#xff0c;甚至能在跨越一个网络的不同计算机的不同进程之…

Zbrush 导出置换 然后导入vray 在 3ds max 和 maya 设置

注&#xff1a;方法很多&#xff0c;这个只是个人学习总结&#xff0c;如果不合适&#xff0c;可另外学习其他方法&#xff01; 第一步&#xff1a; Zbrush 导出置换和法线设置&#xff1a; 第二步&#xff1a; 3Ds max 设置方式建议用exr格式&#xff08;由于导出的时候…

科目一过关技巧

口诀 3让6违——题目中看到“6分”选“违”字&#xff1b;看到“违”字选6分&#xff08;“违”法停车的违字除外&#xff0c;选9分&#xff09;&#xff1b;看到“让”就3分红高蓝低——红色圈圈最高&#xff0c;蓝色最低虚可实禁——车辆可以压虚线&#xff0c;不能压实线&a…