8、如何使用FactoryBean向Spring容器中注册bean?
创始人
2024-02-04 01:12:37

在这里插入图片描述

📫作者简介: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.** 

NB: A bean that implements this interface cannot be used as a normal bean.* A FactoryBean is defined in a bean style, but the object exposed for bean* references ({@link #getObject()}) is always the object that it creates.**

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.**

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.**

{@code FactoryBean} is a programmatic contract. Implementations are not* supposed to rely on annotation-driven injection or other reflective facilities.* {@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.**

The container is only responsible for managing the lifecycle of the FactoryBean* instance, not the lifecycle of the objects created by the FactoryBean. Therefore,* a destroy method on an exposed bean object (such as {@link java.io.Closeable#close()})* will not be called automatically. Instead, a FactoryBean should implement* {@link DisposableBean} and delegate any such close call to the underlying object.**

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 the bean type* @see org.springframework.beans.factory.BeanFactory* @see org.springframework.aop.framework.ProxyFactoryBean* @see org.springframework.jndi.JndiObjectFactoryBean*/ public interface FactoryBean {/*** 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.*

As with a {@link BeanFactory}, this allows support for both the* Singleton and Prototype design pattern.*

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}.*

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*/@NullableT getObject() throws Exception;/*** Return the type of object that this FactoryBean creates,* or {@code null} if not known in advance.*

This allows one to check for specific types of beans without* instantiating objects, for example on autowiring.*

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.*

This method can be called before 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.*

NOTE: 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*/@NullableClass 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)?*

NOTE: 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.*

The singleton status of the FactoryBean itself will generally* be provided by the owning BeanFactory; usually, it has to be* defined as singleton there.*

NOTE: 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}.*

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对象,这个对象会添加到容器中*/@Overridepublic UserService getObject() throws Exception {return new UserService();}@Overridepublic Class getObjectType() {// 返回这个对象的类型return UserService.class;}/*** 是单例吗?* 如果返回true,那么代表这个bean是单实例,在容器中只会保存一份;* 如果返回false,那么代表这个bean是多实例,每次获取都会创建一个新的bean** @return*/@Overridepublic 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方法,代码如下:

   @Testpublic 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**

 @Testpublic 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类

  @Testpublic 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本身。

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...