【spring源码系列】之【FactoryBean类型的接口】

1.概述

目前我们知道,spring创建bean有多种方式,比如xml方式创建,比如@Component,@Service,@Controler,@Repository注解创建,比如@Autowired依赖注入创建,后续还有通过springboot方式的配置注解@Configuration与@Bean方式结合创建,这里不一一介绍,等分析spring boot源码的时候再做总结。

就spring本身,提供了一种接口方式创建bean,就是本节要讨论的通过FactoryBean接口方式创建。

2.实例

FactoryBean接口的实现类FactoryBeanDemo:

package com.wzj.FactoryBean;  import org.springframework.beans.factory.FactoryBean; import org.springframework.stereotype.Service;  @Service public class FactoryBeanDemo implements FactoryBean {      @Override     public Object getObject() throws Exception {         return new FactoryB();     }      @Override     public Class<?> getObjectType() {         return FactoryB.class;     } } 

通过FactoryBean实现类,完成自定义类FactoryB的实例化,FactoryB:

package com.wzj.FactoryBean;  import lombok.Data;  @Data public class FactoryB {     private String name = "wzj"; } 

测试类:

public class TestSpring {      @Autowired     private ApplicationContext applicationContext;      @Test     public void testFactoryBean() {         ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");         FactoryB factoryB = (FactoryB)applicationContext.getBean("factoryBeanDemo");         System.out.println(factoryB);          FactoryBeanDemo factoryBeanDemo = (FactoryBeanDemo)applicationContext.getBean("&factoryBeanDemo");         System.out.println(factoryBeanDemo);     } 

测试结果:

可以看出,当获取名称为factoryBeanDemo的实例时,得到的是getObject()方法里创建的FactoryB类型的对象,而获取加前缀&factoryBeanDemo的实例时,得到的是FactoryBeanDemo本身的实例。

3.源码

step1: FactoryBean 接口的调用入口在实例化和 IOC/DI 做完后,就会调用 FactoryBean 类型的接口如下图所示

    // Create bean instance.     // 创建bean实例     if (mbd.isSingleton()) {      sharedInstance = getSingleton(beanName, () -> {       try {        return createBean(beanName, mbd, args);       }       catch (BeansException ex) {        // Explicitly remove instance from singleton cache: It might have been put there        // eagerly by the creation process, to allow for circular reference resolution.        // Also remove any beans that received a temporary reference to the bean.        destroySingleton(beanName);        throw ex;       }      });      // FactoryBean的调用入口      bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);     } 

step2: 如果要获取到 FactoryBean 类本身,就必须加上&符号,比如 beanFactory.getBean(“&beanName”) ,如下:

 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.   // 如果为name不为空,且以前缀&打头,直接返回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.   if (!(beanInstance instanceof FactoryBean)) {    return beanInstance;   }     
 public static boolean isFactoryDereference(@Nullable String name) {   return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));  } 
 String FACTORY_BEAN_PREFIX = "&"; 

stet3: BeanFactory.getBean(“beanName”)只能获取到 getObject()方法返回的实例。getObject 方法返回的实例会有单独的缓存存储,跟其他实例不是同一个缓存,对应的缓存是:factoryBeanObjectCache

                // 如果是不是以前缀&打头,并且是FactoryBean类型的   Object object = null;   if (mbd != null) {    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;  } 
 protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {   if (factory.isSingleton() && containsSingleton(beanName)) {    synchronized (getSingletonMutex()) {     // 先从缓存factoryBeanObjectCache取     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;    }   }                 ...... 

小结:具体代码参考 getSingleton 方法之后 getObjectForBeanInstance

  • 如果bean实例不是 FactoryBean 类型的或者 name 以&开始的则直接返回实例。
  • 如果bean是 FacotyBean 并且不是以&开头, 会通过方法doGetObjectFromFactoryBean 调用FactoryBean 内部继承实现的 getObject 方法,并且判断一级缓存中如果存在该 bean 实例把实例缓存到factoryBeanObjectCache 对应的 map 中,这个是单独缓存 FactoryBean 类型实例的 map。

4.总结

灵活创建所需实例对象的时候,通过实现FactoryBean接口的getObject方法定义实例化过程。

比如MyBatis提供mybatis-spring项目中的 org.mybatis.spring.SqlSessionFactoryBean

public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {  // ...省略其他代码    public SqlSessionFactory getObject() throws Exception {  if (this.sqlSessionFactory == null) {    afterPropertiesSet();  }   return this.sqlSessionFactory;  } }  

sqlSessionFactory是SqlSessionFactoryBean的一个属性,它的赋值是在通过回调afterPropertiesSet()方法进行的。 因为SqlSessionFactoryBean实现了InitializingBean接口,所以在Spring初始化Bean的时候,能回调afterPropertiesSet()方法。

public void afterPropertiesSet() throws Exception {     // buildSqlSessionFactory()方法会根据mybatis的配置进行初始化。  this.sqlSessionFactory = buildSqlSessionFactory(); }  

在上面的afterPropertiesSet()方法中,buildSqlSessionFactory()方法会根据mybatis的配置,完成客户所需要的的sessionFactory的初始化。

商匡云商
Logo
对比商品
  • 合计 (0)
对比
0
购物车