更多文章点击--spring源码分析系列

1、FactoryBean设计目的以及使用

2、FactoryBean工厂类机制运行机制分析

1、FactoryBean设计目的以及使用

FactoryBean对象设计是为了生成简化对象, 在BeanDefinition加载的时候FactoryBean的beanName会带有特殊前缀&.

public interface FactoryBean<T> {
@Nullable
T getObject() throws Exception; @Nullable
Class<?> getObjectType(); default boolean isSingleton() {
return true;
}
}

在BeanFactory中的定义:

public interface BeanFactory {
// FactoryBean前缀, 用于区分FactoryBean产生的bean. 如果myJndiObject为FactoryBean, 可以用&myJndiObject获取工厂类
/**
* Used to dereference a {@link FactoryBean} instance and distinguish it from
* beans <i>created</i> by the FactoryBean. For example, if the bean named
* {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
* will return the factory, not the instance returned by the factory.
*/
String FACTORY_BEAN_PREFIX = "&";
// .........
}

实际应用中如ProxyFactoryBean可以将代理的具体细节隐藏起来, 只需要通过getObject获取代理.  还有CronTriggerFactoryBean配置使用quartz时候简化配置等. 以下为一个示例demo:

DecorationFactoryBean.java

/**
* bean 装饰工厂
* @author
*/
public class DecorationFactoryBean implements FactoryBean<Bean> {
@Override
public Bean getObject() throws Exception {
Bean bean = new Bean() ;
bean.setName("在FactoryBean统一处理属性") ;
return bean;
} @Override
public Class<?> getObjectType() {
return Bean.class;
}
}

ioc-FactoryBean.xml

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="bean" class="com.nancy.ioc.FactoryBean.DecorationFactoryBean/">
</beans>

ioc-FactoryBean.xml

FactoryBeanTest.java

public class FactoryBeanTest  {

    private ApplicationContext applicationContext ;

    @Before
public void beforeApplicationContext(){
/**
* ApplicationContext 自动注册 BeanPostProcessor、InstantiationAwareBeanPostProcessor、BeanFactoryPostProcessor
* 不需要手动注册
* */
applicationContext = new ClassPathXmlApplicationContext("ioc-FactoryBean.xml") ;
} @Test
public void test(){
Bean bean = (Bean) applicationContext.getBean("bean");
System.out.println(bean);
DecorationFactoryBean factoryBean = (DecorationFactoryBean) applicationContext.getBean("&bean");
System.out.println(factoryBean);
} @After
public void after(){
if(applicationContext != null){
((ClassPathXmlApplicationContext)applicationContext).close();
}
}
}

FactoryBeanTest.java

运行结果, 虽然声明的的是工厂类DecorationFactoryBean, 实际正确返回Bean的实例.

17:11:08.692 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@797badd3
17:11:09.150 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 1 bean definitions from class path resource [ioc-FactoryBean.xml]
17:11:10.974 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean'
Bean{name='在FactoryBean统一处理属性'}
com.nancy.ioc.FactoryBean.DecorationFactoryBean@73eb439a
17:11:39.008 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Closing org.springframework.context.support.ClassPathXmlApplicationContext@797badd3, started on Fri Apr 26 17:11:08 CST 2019

2、FactoryBean工厂类机制运行机制分析

由bean创建过程分析FactoryBean获取bean的流程: 入口 AbstractAutowireCapableBeanFactory.getObjectForBeanInstance

AbstractAutowireCapableBeanFactory.getObjectForBeanInstance

// 重载父类AbstractBeanFactory方法, FactoryBean获取入口
@Override
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
String currentlyCreatedBean = this.currentlyCreatedBean.get();
if (currentlyCreatedBean != null) {
registerDependentBean(beanName, currentlyCreatedBean);
}
return super.getObjectForBeanInstance(beanInstance, name, beanName, mbd);
}

AbstractBeanFactory.getObjectForBeanInstance

/**
* Get the object for the given bean instance, either the bean
* instance itself or its created object in case of a FactoryBean.
* @param beanInstance the shared bean instance
* @param name name that may include factory dereference prefix
* @param beanName the canonical bean name
* @param mbd the merged bean definition
* @return the object to expose for the bean
*/
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 判断是否为工厂Bean 合法性校验
// Don't let calling code try to dereference the factory if the bean isn't a factory.
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
}
// 可以获取工厂Bean本身
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
// 查询缓存是否存
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());
// 使用工厂方法获取bean
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}

FactoryBeanRegistrySupport

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
// 单例对象获取bean
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 实际调用工厂方法获取bean地方
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
// 涉及到bean声明周期BeanPostProcess, 实例话后需要触发
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
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;
}
}

实际调用工厂方法获取bean地方

 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);
} // Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
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;
} @Override
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
return applyBeanPostProcessorsAfterInitialization(object, beanName);
}
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException { Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}

doGetObjectFromFactoryBean

由此串联起来FactoryBean运行机制实质简化复杂的bean生产以及隐藏一些实现的过程.  在众多框架中利用拓展FactoryBean, 减少使用框架使用难度.

spring源码分析系列 (8) FactoryBean工厂类机制的更多相关文章

  1. 【Spring源码分析系列】启动component-scan类扫描加载过程

    原文地址:http://blog.csdn.net/xieyuooo/article/details/9089441/ 在spring 3.0以上大家都一般会配置一个Servelet,如下所示: &l ...

  2. spring源码分析系列

    spring源码分析系列 (1) spring拓展接口BeanFactoryPostProcessor.BeanDefinitionRegistryPostProcessor spring源码分析系列 ...

  3. spring源码分析系列 (2) spring拓展接口BeanPostProcessor

    Spring更多分析--spring源码分析系列 主要分析内容: 一.BeanPostProcessor简述与demo示例 二.BeanPostProcessor源码分析:注册时机和触发点 (源码基于 ...

  4. spring源码分析系列 (5) spring BeanFactoryPostProcessor拓展类PropertyPlaceholderConfigurer、PropertySourcesPlaceholderConfigurer解析

    更多文章点击--spring源码分析系列 主要分析内容: 1.拓展类简述: 拓展类使用demo和自定义替换符号 2.继承图UML解析和源码分析 (源码基于spring 5.1.3.RELEASE分析) ...

  5. spring源码分析系列 (1) spring拓展接口BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor

    更多文章点击--spring源码分析系列 主要分析内容: 一.BeanFactoryPostProcessor.BeanDefinitionRegistryPostProcessor简述与demo示例 ...

  6. spring源码分析系列 (3) spring拓展接口InstantiationAwareBeanPostProcessor

    更多文章点击--spring源码分析系列 主要分析内容: 一.InstantiationAwareBeanPostProcessor简述与demo示例 二.InstantiationAwareBean ...

  7. MyCat源码分析系列之——BufferPool与缓存机制

    更多MyCat源码分析,请戳MyCat源码分析系列 BufferPool MyCat的缓冲区采用的是java.nio.ByteBuffer,由BufferPool类统一管理,相关的设置在SystemC ...

  8. spring源码分析系列 (15) 设计模式解析

    spring是目前使用最为广泛的Java框架之一.虽然spring最为核心是IOC和AOP,其中代码实现中很多设计模式得以应用,代码看起来简洁流畅,在日常的软件设计中很值得借鉴.以下是对一些设计模式的 ...

  9. spring源码分析系列3:BeanFactory核心容器的研究

    目录 @(spring源码分析系列3:核心容器的研究) 在讲容器之前,再明确一下知识点. BeanDefinition是Bean在容器的描述.BeanDefinition与Bean不是一个东西. Be ...

随机推荐

  1. 基于Apache的阿里云部署Node.js服务器(Windows环境)

    1 前言 由于nodejs项目对方开放了多个端口,而且阿里云上的Apache服务器(windows)已经挂载了网站,此时需要把此项目也挂上去,网上查询资料,方法略少,基本是基于nginx版本的. 2  ...

  2. python与redis

    1.什么是redis Redis 是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset ...

  3. 洛谷P2239 螺旋矩阵

    传送门 分析:将整个矩阵看成 "回" 形状的分层结构,然后进行去层处理,使得要求得 \((i,j)\) 处于最外层,然后再分情况讨论.最外面的一层共有数: $ 4 * n - 4 ...

  4. java多线程快速入门(五)

    常用线程api方法 多线程运行状态 1.新建状态 用new创建一个线程 2.就绪状态 当调用线程的start()方法 3.运行状态 当线程获得cpu,开始执行run方法 4.阻塞状态 线程通过调用sl ...

  5. html table标签

    table标签 table的基本样式 table表格的美化 table表格行合并和列合并 table的基本样式: https://blog.csdn.net/lilongsy/article/deta ...

  6. 2018-2019 2 20165203 《网络对抗技术》Exp6 信息搜集与漏洞扫描

    2018-2019 2 20165203 <网络对抗技术>Exp6 信息搜集与漏洞扫描 实践目标 掌握信息搜集的最基础技能与常用工具的使用方法. 实践内容 (1)各种搜索技巧的应用 (2) ...

  7. istringstream、ostringstream、stringstream 类介绍 和 stringstream类 clear函数的真正用途

    istringstream.ostringstream.stringstream 类介绍 和 stringstream类 clear函数的真正用途 来源: http://blog.csdn.net/T ...

  8. 开发同学的福利--mysql监控工具sqlprofiler,类似sqlserver的profiler工具

    最近无意发现了mysql的客户端监控工具“Nero Profile SQL”,刚开始还不知道怎么使用,经过半小时摸索,现将使用步骤写下来. 背景:开发的时候,如果数据存储层这块使用EF,或者其他orm ...

  9. hdu 1757 和1005差不多 (矩阵快速幂)

    If x < 10 f(x) = x.If x >= 10 f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-1 ...

  10. noip2016 天天爱跑步

    没看过正解..应该是些乱七八糟想不出来的东西 解法1: 首先,必须要做的是将每条路径拆成2个直的路径 那么对于那条从深度大的到深度小的路径 dep[x]-dep[y]应该等于观察时间 那么就可以在这些 ...