首页 > 其他分享 >FactoryBean -【Spring底层原理】

FactoryBean -【Spring底层原理】

时间:2024-08-11 13:23:28浏览次数:12  
标签:object Spring beanName null Bean FactoryBean 设计模式 底层

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-aRbqZOiW-1723199879805)]

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

[外链图片转存中…(img-EzQy7gOQ-1723199879806)]

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

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

标签:object,Spring,beanName,null,Bean,FactoryBean,设计模式,底层
From: https://blog.csdn.net/2401_85819474/article/details/141069074

相关文章

  • 深入浅出!这份阿里内传的“Spring-MVC源码分析与实践笔记”带你看透Spring-MVC源码!太牛
    第二章常见协议和标准DNS协议TCP/IP协议与SocketHTTP协议Servlet与JavaWeb开发第三章DNS的设置DNS解析Windows7设置DNS服务器Windows设置本机域名和IP的对应关系第四章Java中Socket的用法普通Socket的用法NioSocket的用法第五章自己动手实现HTTP协议第六......
  • [纯干货]SpringCould + 适配器模式 + nacos动态部署 OSS 对接
    一、前言在一个微服务项目里,我们的OSS云存储服务常常需要配置诸如阿里云、腾讯云、minio等多个云存储厂商的业务代码,而且后续无法确保是否会增添新的云存储厂商。此时,倘若我们要修改具体使用的云存储厂商,就会致使controller层和service层发生变动,这并不符合低耦合的理......
  • springMVC 请求流程解析
    @SuppressWarnings("deprecation")protectedvoiddoDispatch(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{ //实际处理时用的请求,如果不是上传请求,则直接使用接收到的request,否则封装成上传的request HttpServletRequestprocessedRequ......
  • AJAX - 利用XML和Promise封装简易版axios,了解axios底层原理
     AJAX原理-XMLHttpRequest定义:XMLHttpRequest(XHR)对象用于与服务器交互。通过XMLHttpRequest可以在不刷新页面的情况下请求特定URL,获取数据。这允许网页在不影响用户操作的情况下,更新页面的局部内容。XMLHttpRequest 在 AJAX 编程中被大量使用。关系:axios内部采用......
  • springboot打包程序操作
    打包作用:我们打包的主要目的就是为了不使用idea也能够运行程序,能够把这个程序给放到服务器上去运行。第一部分:打包程序(1)首先把所有的页面都关掉,确保有一个干净的页面:(2)然后在右侧的maven部分点击package操作,并等待执行一段时间:(3)打包成功的结果第二部分:找到打包程序(1)在......
  • springboot整合redis
    第一部分:redis的下载安装百度网盘下载:通过百度网盘分享的文件:Redis-x64-5.0.14.zip链接:https://pan.baidu.com/s/1GEQj4p0l4fy1DzwCIknpRg?pwd=qokq 提取码:qokq --来自百度网盘超级会员V5的分享第二部分:安装(1)双击打开软件(2)点击next(3)点击next(4)更改路径,点击next......
  • 基于SpringBoot+Vue+uniapp的心理测评系统(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • 基于SpringBoot+Vue+uniapp的直播电商交流平台(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • 毕业设计:基于springboot的上门维修系统微信小程序【代码+论文+PPT】
    全文内容包括:1、采用技术;2、系统功能;3、系统截图;4、配套内容。索取方式见文末微信号,欢迎关注收藏!一、采用技术语言:Java1.8框架:SpringBoot数据库:MySQL5.7、8.0开发工具:IntelliJIDEA旗舰版、微信开发工具其他:Maven3.8以上二、系统功能用户管理:负责注册用户的信息维护,包括......
  • 【Java毕设选题推荐】基于SpringBoot的springbootOA公文发文管理系统
    前言:我是IT源码社,从事计算机开发行业数年,专注Java领域,专业提供程序设计开发、源码分享、技术指导讲解、定制和毕业设计服务......