Spring-FactoryBean解析

引言

    我们使用spring的时候,初始化一个bean的时候一般使用的是DI去注入依赖的;但是如果一个bean的初始化及其复杂,或者你想干预一个bean的初始化,你要如何办?那就是使用FactoryBean
    我们使用的mybatis和spring结合,注入SqlSessionFactory的时候就是依赖于SqlSessionFactoryBean完成的。

注意

我们一个bean的初始化会经过:(初始化–调用aware接口—bean的前置处理–bean的init方法–bean的后置处理);FactoryBean是会经历这个过程的,但是里面构造的那个对象bean是不会经历这个过程的。

FactoryBean和BeanFactory区别?
    FactoryBean是一个工厂Bean,可以生成某一个类型Bean实例,它最大的一个作用是:可以让我们自定义Bean的创建过程。
    BeanFactory是Spring容器中的一个基本类(ioc容器),在BeanFactory中可以创建和管理Spring容器中的Bean,它对于Bean的创建有一个统一的流程。

FactoryBean接口测试

public interface FactoryBean<T> {

    //返回的对象实例
    T getObject() throws Exception;
    //Bean的类型
    Class<?> getObjectType();
    //true是单例,false是非单例
    boolean isSingleton();
}
public class Cat {
    int age;

    public Cat() {
        System.err.println("Cat初始化成功");
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
/**
 * FactoryBean不可以使用自动注入
 *    1.在ioc容器存放到 FactoryBean  &可以通过&beanName获得
 *    2.getbean获取FactoryBean的时候会判断是否FactoryBean  1.第一次调用getObject获取对象,后面在缓存中获取。
 */
@Component
public class DriverFactoryBean implements FactoryBean {

    public DriverFactoryBean() {
        System.out.println("DriverFactoryBean初始化");
    }

    @Override
    public Object getObject() throws Exception {
        return new Cat();
    }

    @Override
    public Class<?> getObjectType() {
        return Cat.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

getBean中&FactoryBeanName和FactoryBeanName 获取bean的不同

&FactoryBeanName:获取的是FactoryBean本身这个对象
FactoryBeanName :获取的是FactoryBean中getObject方法构造出来的对象

在这里插入图片描述
在这里插入图片描述

Spring源码分析

首先看一下FactoryBean本身创建过程和其他bean是一样的,无非就是:

  1. 获取FactoryBean的bean定义信息
  2. 调用beanfactory的后置处理器
  3. 冻结bean定义信息,进行bean的初始化工作
  4. 调用构造函数,构造出一个初始bean
  5. 之后进行bean的属性填出
  6. 调用一系列实现的aware接口,进行增强
  7. 调用bean的前置处理
  8. 调用bean的*init方法
  9. 调用bean的后置处理
  10. 使用bean
  11. 销毁bean

前面这些步骤百度上查询一大堆,我们这里说的是FactoryBean中的构造对象是如何被初始化调用的。

这里提出几个问题,带的问题去研究?

1.为什么&FactoryBeanName和FactoryBeanName 获取bean的不同
2.使用FactoryBean注入的对象什么时候初始化?是不是在容器启动的时候?
3.普通的bean对象存放的缓存和FactoryBean注入的对象是一个缓存么?

我们这里直接这个入口分析:

public class App {

    public static void main(String[] args) {
       /* SpringApplication.run(App.class,args);*/
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
        Object cat = ctx.getBean("&driverFactoryBean");
    }

}

ClassPathXmlApplicationContext .getBean()

public Object getBean(String name) throws BeansException {
		assertBeanFactoryActive();//判断spring容器状态
		//1.获取bean工厂后去获取bean
		//这里beanfactory是DefaultListableBeanFactory
		return getBeanFactory().getBean(name);
	}

DefaultListableBeanFactory是继承AbstractBeanFactory
所以getBeanFactory().getBean(name)方法跳转到AbstractBeanFactory

public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}

这里doGetBean调用的是本类的重载方法
1.首先在三级缓存池里面寻找bean,因为这里在容器启动的时候已经把factorybean放入了。
2.如果找到,就去判断是不是factorybean需要返回

protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {
  
		String beanName = transformedBeanName(name);
		Object beanInstance;

		// Eagerly check singleton cache for manually registered singletons.
		Object sharedInstance = getSingleton(beanName);//首先在单列缓存池里面寻找bean
		//如果找到,就去判断是不是factorybean需要返回
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
		//下面还有逻辑.......我们这里不看
}

下来我们看一下 如何去判断factorybean并且返回合适的对象

beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);

里面做了什么?

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

		// Don't let calling code try to dereference the factory if the bean isn't a factory.
		//这里会判断bean的名字是否携带以&开头,如果是直接返回
		if (BeanFactoryUtils.isFactoryDereference(name)) {
			if (beanInstance instanceof NullBean) {
				return beanInstance;
			}
			if (!(beanInstance instanceof FactoryBean)) {
				throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
			}
			if (mbd != null) {
				mbd.isFactoryBean = true;
			}
			return beanInstance;
		}

		// 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.
		//检查是否FactoryBean
		if (!(beanInstance instanceof FactoryBean)) {
			return beanInstance;
		}

		Object object = null;
		//设置RootBeanDefinition 是否为空
		if (mbd != null) {
		   //设置FactoryBean
			mbd.isFactoryBean = true;
		}
		else {
		   //在FactoryBean缓存池里面获取
			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;
	}

如何初始化?

object = getObjectFromFactoryBean(factory, beanName, !synthetic);
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
         //判断是否单列和单列缓存包含这个FactoryBean
		if (factory.isSingleton() && containsSingleton(beanName)) {
		   //同步锁 锁住单列缓池
			synchronized (getSingletonMutex()) {
			    //再次缓存中获取
				Object object = this.factoryBeanObjectCache.get(beanName);
				if (object == null) {
				    //这里调用getObject()获取对象
					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 {
						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;
		}
	}

如何调用getObject()方法的

object = doGetObjectFromFactoryBean(factory, beanName);
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, 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 {
			    //这里就找到了getObject
				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;
	}

总结

1.为什么&FactoryBeanName和FactoryBeanName 获取bean的不同
&FactoryBeanName是直接在bean的单列缓存里面获取拿的是FactoryBean
而FactoryBeanName 是在FactoryBean的缓存里面获取的bean
在这里插入图片描述在这里插入图片描述在这里插入图片描述

2.使用FactoryBean注入的对象什么时候初始化?
FactoryBean这个对象是在容器启动的时候就缓存在单列缓存
FactoryBean里面的注入对象,是在第一次获取对象的时候调用getObject方法初始化的,就面缓存在FactoryBean的缓存里面

3.普通的bean对象存放的缓存和FactoryBean注入的对象是一个缓存么?
肯定不是,普通的bean对象是存放在我们三级缓存里面的
FactoryBean注入的对象是存放在一个单独的缓存里面的FactoryBean的缓存
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值