FactoryBean -【Spring底层原理】

FactoryBean作为一个生产或修饰对象的工厂Bean,那是如何生产Bean的呢,咱们通过实例来进行分析,这里就使用工厂Bean来生产Color对象

// 启动类

public class MainTest {

@Test

public void TestMain(){

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

String[] beanNames = applicationContext.getBeanDefinitionNames();

for (String beanName : beanNames) {

System.out.println(beanName);

}

// 工厂Bean获取的是getObject创建的对象

Object factoryBean = applicationContext.getBean(“colorFactoryBean”);

System.out.println(“Bean的类型” + factoryBean.getClass());

// 测试isSingleton控制单例多例

Object factoryBean2 = applicationContext.getBean(“colorFactoryBean”);

System.out.println(“Bean的类型” + factoryBean.getClass());

System.out.println(factoryBean == factoryBean2);

// 通过加“&”获取ColorFactoryBean对象

Object factoryBean3 = applicationContext.getBean(“&colorFactoryBean”);

System.out.println(factoryBean3.getClass());

}

}

// 待生产的Color对象

public class Color {

}

// 创建一个spring定义的工厂Bean

public class ColorFactoryBean implements FactoryBean {

// 返回一个color对象,这个对象会添加到容器中

public Object getObject() throws Exception {

return new Color();

}

// Bean的类型

public Class<?> getObjectType() {

return Color.class;

}

// 控制是否是单例,返回true为单例(容器中保存一份),返回false为多例(每次获取调用getObject()创建新的)

public boolean isSingleton() {

return false;

}

}

// 配置类

@Configuration

public class AppConfig {

/**

  • 1.默认获取的是工厂Bean调用getObject创建的对象

  • 2.要获取工厂Bean本身,需要给ID前面加一个“&”

*/

@Bean

public ColorFactoryBean colorFactoryBean(){

return new ColorFactoryBean();

}

}

运行启动类,可以看到,已经将Bean对象给生产出来了,根据打印信息,可以得出以下结论:

  • 工厂Bean获取的是getObject所创建的对象,这也就是所谓的生产Bean

  • 通过改变工厂类的isSingleton方法返回值可以改变创建Bean的单例还是多例

  • 如果要将FactoryBean本身注入进spring容器中,获取的时候需要给ID前面加一个“&”

image-20210301164656868

三、源码追踪

参考:https://www.cnblogs.com/guitu18/p/11284894.html

FactoryBean是怎么让Spring容器管理调用它的getObject所生成的Bean的,咱们通过源码来看看FactorBean是如何生产Bean的,

在启动类中通过调用:AnnotationConfigApplicationContext——> refresh() 方法——> getBean()方法,再到AbstractBeanFactory实现类,在这个类中,又调用了doGetBean方法,doGetBean可以说是Spring容器中一个很核心的一个类,里面的功能很多很复杂,我们在这篇文章中只关注和FactoryBean相关的内容。截取部分代码:

【1】doGetBean方法中调用getSingleton方法 从Spring容器中获取单例Bean

protected T doGetBean(String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {

String beanName = this.transformedBeanName(name);

// 调用getSingleton方法 从Spring容器中获取单例Bean

Object sharedInstance = this.getSingleton(beanName);

Object bean;

if (sharedInstance != null && args == null) {

if (this.logger.isTraceEnabled()) {

if (this.isSingletonCurrentlyInCreation(beanName)) {

this.logger.trace(“Returning eagerly cached instance of singleton bean '” + beanName + “’ that is not fully initialized yet - a consequence of a circular reference”);

} else {

this.logger.trace(“Returning cached instance of singleton bean '” + beanName + “'”);

}

}

bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);

}

}

getSingleton从Spring容器中获取单例Bean

@Nullable

public Object getSingleton(String beanName) {

return this.getSingleton(beanName, true);

}

@Nullable

protected Object getSingleton(String beanName, boolean allowEarlyReference) {

// 先从singletonObjects中获取单例Bean singletonObjects是一个ConcurrentHashMap

// key是beanName value是单例Bean

Object singletonObject = this.singletonObjects.get(beanName);

// 如果没有获取到,则判断是不是当前在创建中的单例Bean

if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {

singletonObject = this.earlySingletonObjects.get(beanName);

if (singletonObject == null && allowEarlyReference) {

synchronized(this.singletonObjects) {

singletonObject = this.singletonObjects.get(beanName);

if (singletonObject == null) {

singletonObject = this.earlySingletonObjects.get(beanName);

if (singletonObject == null) {

ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);

if (singletonFactory != null) {

singletonObject = singletonFactory.getObject();

this.earlySingletonObjects.put(beanName, singletonObject);

this.singletonFactories.remove(beanName);

}

}

}

}

}

}

return singletonObject;

}

【2】doGetBean方法中调用getObjectForBeanInstance,关键代码就从这里开始,查看源码:

protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

// 这里判断 name是不是以&开头,不是经过处理的beanName 并且这个bean实例 不是FactoryBean类型的

// 如果是&开头并且不是FactoryBean类型 则抛出异常

if (BeanFactoryUtils.isFactoryDereference(name)) {

if (beanInstance instanceof NullBean) {

return beanInstance;

// 不是FactoryBean类型 或者name以&开头 直接返回bean实例,要根据beanName获取真正的FactoryBean实例的时候,在beanName前面加上&

} else if (!(beanInstance instanceof FactoryBean)) {

throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());

} else {

if (mbd != null) {

mbd.isFactoryBean = true;

}

return beanInstance;

}

} else if (!(beanInstance instanceof FactoryBean)) {

return beanInstance;

} else {

Object object = null;

if (mbd != null) {

mbd.isFactoryBean = true;

} else {

// factoryBeanObjectCache 看看是不是在缓存中存在

object = this.getCachedObjectForFactoryBean(beanName);

}

// 如果没有

if (object == null) {

// 如果能走到这里来 这个bean实例是FactoryBean类型的

FactoryBean<?> factory = (FactoryBean)beanInstance;

if (mbd == null && this.containsBeanDefinition(beanName)) {

mbd = this.getMergedLocalBeanDefinition(beanName);

}

boolean synthetic = mbd != null && mbd.isSynthetic();

//从这个方法的名字我们可以看到这个方法的意思是:从FactoryBean中获取对象

object = this.getObjectFromFactoryBean(factory, beanName, !synthetic);

}

return object;

}

}

分析如下:

  1. 第一个判断BeanFactoryUtils.isFactoryDereference:判断name是否不为空且以&开头,如果是&开头并且不是FactoryBean类型 则抛出异常
  1. 后面的判断beanInstance instanceof FactoryBean:不是FactoryBean类型 或者name以&开头 直接返回bean实例,要根据beanName获取真正的FactoryBean实例的时候,在beanName前面加上&

public static boolean isFactoryDereference(@Nullable String name) {

return name != null && name.startsWith(“&”);

}

如果beanInstance不属于FactoryBean或其子类的实例,或者name是以&开头就直接返回实例对象beanInstance,否则进入到if分支中。在if分支里的各种if .. ==null判断是为了提高性能,咱们只挑关键部分看:object = this.getObjectFromFactoryBean(factory, beanName, !synthetic);继续跟踪进去看代码。

【3】getObjectFromFactoryBean调用doGetObjectFromFactoryBean方法

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {

// FactoryBean类型的实例 调用isSingleton方法返回的是true,所传入的bean实例也要求是单例类型的

if (factory.isSingleton() && this.containsSingleton(beanName)) {

synchronized(this.getSingletonMutex()) {

Object object = this.factoryBeanObjectCache.get(beanName);

if (object == null) {

// 调用doGetObjectFromFactoryBean方法从FactoryBean中获取bean对象,这里是调用的FactoryBean的getObject方法来获取的

object = this.doGetObjectFromFactoryBean(factory, beanName);

// 再从缓存中获取一次

Object alreadyThere = this.factoryBeanObjectCache.get(beanName);

// 如果上一步的缓存中获取到了则用缓存中的替代我们从FactoryBean中获取的bean

if (alreadyThere != null) {

object = alreadyThere;

} else {

if (shouldPostProcess) {

if (this.isSingletonCurrentlyInCreation(beanName)) {

return object;

}

this.beforeSingletonCreation(beanName);

try {

object = this.postProcessObjectFromFactoryBean(object, beanName);

} catch (Throwable var14) {

throw new BeanCreationException(beanName, “Post-processing of FactoryBean’s singleton object failed”, var14);

} finally {

this.afterSingletonCreation(beanName);

}

}

if (this.containsSingleton(beanName)) {

this.factoryBeanObjectCache.put(beanName, object);

}

}

}

return object;

}

} else {

Object object = this.doGetObjectFromFactoryBean(factory, beanName);

if (shouldPostProcess) {

try {

object = this.postProcessObjectFromFactoryBean(object, beanName);

} catch (Throwable var17) {

言尽于此,完结

无论是一个初级的 coder,高级的程序员,还是顶级的系统架构师,应该都有深刻的领会到设计模式的重要性。

  • 第一,设计模式能让专业人之间交流方便,如下:

程序员A:这里我用了XXX设计模式

程序员B:那我大致了解你程序的设计思路了

  • 第二,易维护

项目经理:今天客户有这样一个需求…

程序员:明白了,这里我使用了XXX设计模式,所以改起来很快

  • 第三,设计模式是编程经验的总结

程序员A:B,你怎么想到要这样去构建你的代码

程序员B:在我学习了XXX设计模式之后,好像自然而然就感觉这样写能避免一些问题

  • 第四,学习设计模式并不是必须的

程序员A:B,你这段代码使用的是XXX设计模式对吗?

程序员B:不好意思,我没有学习过设计模式,但是我的经验告诉我是这样写的

image

从设计思想解读开源框架,一步一步到Spring、Spring5、SpringMVC、MyBatis等源码解读,我都已收集整理全套,篇幅有限,这块只是详细的解说了23种设计模式,整理的文件如下图一览无余!

image

搜集费时费力,能看到此处的都是真爱!

  • 第一,设计模式能让专业人之间交流方便,如下:

程序员A:这里我用了XXX设计模式

程序员B:那我大致了解你程序的设计思路了

  • 第二,易维护

项目经理:今天客户有这样一个需求…

程序员:明白了,这里我使用了XXX设计模式,所以改起来很快

  • 第三,设计模式是编程经验的总结

程序员A:B,你怎么想到要这样去构建你的代码

程序员B:在我学习了XXX设计模式之后,好像自然而然就感觉这样写能避免一些问题

  • 第四,学习设计模式并不是必须的

程序员A:B,你这段代码使用的是XXX设计模式对吗?

程序员B:不好意思,我没有学习过设计模式,但是我的经验告诉我是这样写的

[外链图片转存中…(img-E2d0Kqg1-1723295121188)]

从设计思想解读开源框架,一步一步到Spring、Spring5、SpringMVC、MyBatis等源码解读,我都已收集整理全套,篇幅有限,这块只是详细的解说了23种设计模式,整理的文件如下图一览无余!

[外链图片转存中…(img-4kgfbg3c-1723295121188)]

搜集费时费力,能看到此处的都是真爱!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值