IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring源码之FactoryBean接口的作用和实现原理 -> 正文阅读

[Java知识库]Spring源码之FactoryBean接口的作用和实现原理

1.FactoryBean 接口简述

BeanFactoryFactoryBean 接口,相信很多刚翻看 Spring 源码跟我一样很好奇这俩货怎么长得这么像,分别都是干啥用的。BeanFactorySpringBean 工厂的顶层接口,也是我们常说的 Spring IOC 容器,它定下了 IOC 容器的一些规范和常用方法并管理着 Spring 中所有的 Bean,今天我们不讲它,我们看一下后面那个 FactoryBean

public interface FactoryBean<T> {

	@Nullable
	T getObject() throws Exception;

	@Nullable
	Class<?> getObjectType();

	default boolean isSingleton() {
		return true;
	}
}

先说下 FactoryBean 和其作用再开始分析:首先它是一个 Bean,但又不仅仅是一个 Bean。它是一个能生产或修饰对象生成的工厂 Bean,类似于设计模式中的工厂模式和装饰器模式。它能在需要的时候生产一个对象,且不仅仅限于它自身,它能返回任何 Bean 的实例

2.FactoryBeanSpring 中的应用

Spring 中我们的 Bean 都会被 SpringIOC 容器所管理,在 AbstractApplicationContext 中有一个很重要的方法:refresh(),项目启动或重启的时候 refresh() 会调用 getBean() 初始化所有的 Bean,这个 getBean() 最终会指向 AbstractBeanFactory 中的 getBean() 方法。上述方法的调用链过长,我们不过多赘述,详细的 getBean() 源码 在这里

AbstractBeanFactory 抽象类中,不管是根据名称还是根据类型,getBean() 方法最终都会调用 doGetBean() 方法

2.1.doGetBean()

doGetBean() 方法中一开始就获取了名称 beanName 和实例 sharedInstance

@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
		@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

	final String beanName = transformedBeanName(name);
	Object bean;

	// 方法解释如下图
	Object sharedInstance = getSingleton(beanName);
	// 如果已经初始化过,直接从缓存中获取
	if (sharedInstance != null && args == null) {
		if (logger.isDebugEnabled()) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
						"' that is not fully initialized yet - a consequence of a circular reference");
			}
			else {
				logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
			}
		}	
		// 如果 sharedInstance 是普通的单例 bean,下面的方法会直接返回。但如果
		// 是 FactoryBean 类型的,则需调用 getObject 工厂方法获取真正的 bean 实例
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}
	else {
		// 如果是原型不应该在初始化的时候创建,在这里直接抛出异常
		if (isPrototypeCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
		BeanFactory parentBeanFactory = getParentBeanFactory();
		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
			// 将别名解析成真正的beanName
			String nameToLookup = originalBeanName(name);
			// 如果parentBeanFactory存在,并且beanName在当前BeanFactory不存在Bean定义,则尝试从parentBeanFactory中获取bean实例
			if (parentBeanFactory instanceof AbstractBeanFactory) {
				return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
						nameToLookup, requiredType, args, typeCheckOnly);
			}
			// 尝试在parentBeanFactory中获取bean对象实例
			else if (args != null) {
				return (T) parentBeanFactory.getBean(nameToLookup, args);
			}
			else {
				return parentBeanFactory.getBean(nameToLookup, requiredType);
			}
		}
		if (!typeCheckOnly) {
			markBeanAsCreated(beanName);
		}
		try {
			// 根据beanName重新获取MergedBeanDefinition
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);
			String[] dependsOn = mbd.getDependsOn();
			if (dependsOn != null) {
				// 遍历当前bean依赖的bean名称集合
				for (String dep : dependsOn) {
					// 检查dep是否依赖于beanName,即检查是否存在循环依赖
					if (isDependent(beanName, dep)) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
					}
					// 将dep和beanName的依赖关系注册到缓存中
					registerDependentBean(dep, beanName);
					try {
						getBean(dep);
					}
					catch (NoSuchBeanDefinitionException ex) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
					}
				}
			}
			// scope为 singleton 的bean创建
			if (mbd.isSingleton()) {
				sharedInstance = getSingleton(beanName, () -> {
					try {
						// 创建Bean实例
						return createBean(beanName, mbd, args);
					}
					catch (BeansException ex) {
						destroySingleton(beanName);
						throw ex;
					}
				});
				// 返回beanName对应的实例对象
				// 这里主要处理实现了FactoryBean的情况,需要调用重写的getObject()方法来获取实际的Bean实例
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}				
			// scope为 prototype 的bean创建
			else if (mbd.isPrototype()) {			
				Object prototypeInstance = null;
				try {
					// 创建实例前的操作(将beanName保存到prototypesCurrentlyInCreation缓存中)
					beforePrototypeCreation(beanName);
					// 创建Bean实例
					prototypeInstance = createBean(beanName, mbd, args);
				}
				finally {
					// 创建实例后的操作(将创建完的beanName从prototypesCurrentlyInCreation缓存中移除)
					afterPrototypeCreation(beanName);
				}
				// 返回beanName对应的实例对象
				// 这里主要处理实现了FactoryBean的情况,需要调用重写的getObject()方法来获取实际的Bean实例
				bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
			}
			else {
				// 既不是单例也不是原型的 bean创建,可能是 request之类的
				// 根据scopeName,从缓存拿到scope实例
				String scopeName = mbd.getScope();
				final Scope scope = this.scopes.get(scopeName);
				if (scope == null) {
					throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
				}
				try {
					// 既不是单例也不是原型的bean创建
					Object scopedInstance = scope.get(beanName, () -> {
						// 创建实例前的操作(将beanName保存到prototypesCurrentlyInCreation缓存中)
						beforePrototypeCreation(beanName);
						try {
							return createBean(beanName, mbd, args);
						}
						finally {
							// 创建实例后的操作(将创建完的beanName从prototypesCurrentlyInCreation缓存中移除)
							afterPrototypeCreation(beanName);
						}
					});
					// 返回beanName对应的实例对象
					bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
				}
				catch (IllegalStateException ex) {
					throw new BeanCreationException(beanName,
							"Scope '" + scopeName + "' is not active for the current thread; consider " +
							"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
							ex);
				}
			}
		}
		catch (BeansException ex) {
			cleanupAfterBeanCreationFailure(beanName);
			throw ex;
		}
	}
	// ...... 省略
	return (T) bean;
}
  • transformedBeanName() 是为了获取 bean 真正的名称,它会去掉 name 前面的 &
  • getSingleton() 是从父类 DefaultSingletonBeanRegistrygetSingleton() 方法中的 singletonObjects 一级缓存中取的这个 bean 的实例

在这里插入图片描述
回到 doGetBean() 方法中,拿到 sharedInstance 后,后面的一大堆操作做了单例、多例等判断,最终会走到 getObjectForBeanInstance(),关键部分就在这个方法中,进入方法代码

2.1.1.getObjectForBeanInstance()

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

	// 如果 name 不为空且以 & 开头
	if (BeanFactoryUtils.isFactoryDereference(name)) {
		// beanInstance 属于 NullBean 或其子类的实例
		if (beanInstance instanceof NullBean) {
			return beanInstance;
		}
		if (!(beanInstance instanceof FactoryBean)) {
			throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
		}
	}
	// beanInstance 不是属于 FactoryBean 或其子类的实例,或 name 不为空且以 & 开头
	if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
		return beanInstance;
	}
	
	// 只有当 name 不为空且以 & 开头,并且 beanInstance 属于 FactoryBean 或其子类的实例时,才会执行下面
	Object object = null;
	if (mbd == null) {
		object = getCachedObjectForFactoryBean(beanName);
	}
	if (object == null) {
		// Return bean instance from factory.
		FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
		// Caches object obtained from FactoryBean if it is a singleton.
		if (mbd == null && containsBeanDefinition(beanName)) {
			mbd = getMergedLocalBeanDefinition(beanName);
		}
		boolean synthetic = (mbd != null && mbd.isSynthetic());
		// 关键部分,如下
		object = getObjectFromFactoryBean(factory, beanName, !synthetic);
	}
	return object;
}

2.1.1.1.getObjectFromFactoryBean()

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
	if (factory.isSingleton() && containsSingleton(beanName)) {
		synchronized (getSingletonMutex()) {
			Object object = this.factoryBeanObjectCache.get(beanName);
			if (object == null) {
				// 关键部分
				object = doGetObjectFromFactoryBean(factory, beanName);
				Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
				if (alreadyThere != null) {
					object = alreadyThere;
				}
				else {
					if (shouldPostProcess) {
						if (isSingletonCurrentlyInCreation(beanName)) {						
							return object;
						}
						beforeSingletonCreation(beanName);
						try {
							object = postProcessObjectFromFactoryBean(object, beanName);
						}
						catch (Throwable ex) {
							throw new BeanCreationException(beanName,
									"Post-processing of FactoryBean's singleton object failed", ex);
						}
						finally {
							afterSingletonCreation(beanName);
						}
					}
					if (containsSingleton(beanName)) {
						this.factoryBeanObjectCache.put(beanName, object);
					}
				}
			}
			return object;
		}
	}
	else {
		// 关键部分
		Object object = doGetObjectFromFactoryBean(factory, beanName);
		if (shouldPostProcess) {
			try {
				object = postProcessObjectFromFactoryBean(object, beanName);
			}
			catch (Throwable ex) {
				throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
			}
		}
		return object;
	}
}
2.1.1.1.1.doGetObjectFromFactoryBean()
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
		throws BeanCreationException {

	Object object;
	try {
		if (System.getSecurityManager() != null) {
			AccessControlContext acc = getAccessControlContext();
			try {
				object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
			}
			catch (PrivilegedActionException pae) {
				throw pae.getException();
			}
		}
		else {
			// 关键代码
			object = factory.getObject();
		}
	}
	catch (FactoryBeanNotInitializedException ex) {
		throw new BeanCurrentlyInCreationException(beanName, ex.toString());
	}
	catch (Throwable ex) {
		throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
	}

	if (object == null) {
		if (isSingletonCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(
					beanName, "FactoryBean which is currently in creation returned null from getObject");
		}
		object = new NullBean();
	}
	return object;
}
  • 关键代码 object = factory.getObject() 这个 factory 就是我们传入的 beanInstance 实例。绕了这么一大圈,getBean() 方法返回的居然是我们实现 FactoryBean 接口定义的 getObject() 方法

3.总结

3.1.FactoryBean 接口的作用

一般情况下,Spring 通过反射机制利用的 class 属性指定实现类实例化 Bean,在某些情况下,实例化 Bean 过程比较复杂,如果按照传统的方式,则需要在中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。 Spring 为此提供了一个 org.springframework.bean.factory.FactoryBean 的工厂类接口,用户可以通过实现该接口定制实例化 Bean 的逻辑。FactoryBean 接口对于 Spring 框架来说占用重要的地位,Spring 自身就提供了 70 多个 FactoryBean 的实现。它们隐藏了实例化一些复杂 Bean 的细节,给上层应用带来了便利

FactoryBean 是一个能生产或修饰对象生成的工厂 Bean一个 Bean 如果实现了 FactoryBean 接口,那么根据该 Bean 的名称获取到的实际上是 getObject() 返回的对象,而不是这个 Bean 自身实例,如果要获取这个 Bean 自身实例,那么需要在名称前面加上 & 符号

4.测试验证

下面通过代码测试验证上面的流程,先定义一个 Bean 实现 FactoryBean 接口

@Component
public class MyBean implements FactoryBean {

    private String message;
    
    public MyBean() {
        this.message = "通过构造方法初始化实例";
    }
    
    @Override
    public Object getObject() throws Exception {
        MyBean myBean = new MyBean();
        myBean.message = "通过FactoryBean.getObject()创建实例";
        // 这里并不一定要返回MyBean自身的实例,可以是其他任何对象的实例
        return myBean;
    }
    
    @Override
    public Class<?> getObjectType() {
        return MyBean.class;
    }
    
    public String getMessage() {
        return message;
    }
}

MyBean 实现了 FactoryBean 接口的两个方法,getObject() 是可以返回任何对象的实例的,这里测试就返回 MyBean 自身实例,且返回前给 message 字段赋值。同时在构造方法中也为 message 赋值。然后测试代码中先通过名称获取 Bean 实例,打印 message 的内容,再通过 &+名称 获取实例并打印 message 内容

@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class)
public class FactoryBeanTest {

    @Autowired
    private ApplicationContext context;
    
    @Test
    public void test() {
        MyBean myBean1 = (MyBean) context.getBean("myBean");
        System.out.println("myBean1 = " + myBean1.getMessage());
        MyBean myBean2 = (MyBean) context.getBean("&myBean");
        System.out.println("myBean2 = " + myBean2.getMessage());
        System.out.println("myBean1.equals(myBean2) = " + myBean1.equals(myBean2));
    }
}

结果如下

myBean1 = 通过FactoryBean.getObject()初始化实例
myBean2 = 通过构造方法初始化实例
myBean1.equals(myBean2) = false
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-08 22:14:58  更:2022-03-08 22:19:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:25:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码