引言
我们使用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是一样的,无非就是:
- 获取FactoryBean的bean定义信息
- 调用beanfactory的后置处理器
- 冻结bean定义信息,进行bean的初始化工作
- 调用构造函数,构造出一个初始bean
- 之后进行bean的属性填出
- 调用一系列实现的aware接口,进行增强
- 调用bean的前置处理
- 调用bean的*init方法
- 调用bean的后置处理
- 使用bean
- 销毁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的缓存