FactoryBean被称为工厂Bean。在Spring中是个接口,用它可以生成某一个类型Bean的实例,其最大的一个作用是:可以让我们自定义Bean的创建过程。
在使用Spring时,我们通过在xml中配置
但在某些情况下,如果实例化Bean过程比较复杂,再按照上面传统的方式去创建Bean,则需要在
当然有了,我们还可以使用编码的方式创建Bean。
Spring为此提供了一个org.springframework.bean.factory.FactoryBean接口,程序员可以通过实现该接口采用编码的方式自定义实例化Bean的逻辑。
FactoryBean接口在Spring框架具有极其重要的地位,Spring自身就提供了70多个FactoryBean的实现,这些FactoryBean隐藏了实例化一些复杂Bean的细节,给上层应用带来了极大便利,下面看FactoryBean源码:
// FactoryBean接口 public interface FactoryBean{ //返回对象实例 T getObject() throws Exception; //创建bean的Class类型 Class> getObjectType(); //true是单例,false是非单例,可以看出默认为单例的 default boolean isSingleton() { return true; } }
FactoryBean是一个泛型类且只有三个方法,如果你想要的类是一个单例,那么只需要实现两个方法就可以了,getObject()方法返回一个对象的实例,getObjectType()方法返回对象的Class类型。
看下面一个例子:
// 配置类
@Configuration
@ComponentScan("com.scorpios")
public class AppConfig {
}
// FactoryBean工厂
@Component
public class MasterFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
// 创建一个类
return new Master();
}
@Override
public Class> getObjectType() {
// 返回类的类型
return Master.class;
}
@Override
public boolean isSingleton() {
// 单例
return true;
}
}
// 测试方法
public static void main( String[] args )
{
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.register(AppConfig.class);
annotationConfigApplicationContext.refresh();
Master master = (Master) annotationConfigApplicationContext.getBean("masterFactoryBean");
MasterFactoryBean masterFactoryBean = (MasterFactoryBean) annotationConfigApplicationContext.getBean("&masterFactoryBean");
System.out.println("-----------------------------");
System.out.println(master);
System.out.println(masterFactoryBean);
}
打印结果:
MasterFactoryBean类用@Component注解修饰,如果没有给组件添加别名,那么默认是类名第一个字母小写,即masterFactoryBean。当我们去容器中取masterFactoryBean的时候,就拿到Master类型。
在获取FactoryBean的时候,其实返回的是方法getObject()的值,如果想要获取MasterFactoryBean类本身,需要加上在前面加上&符号才能获取MasterFactoryBean工厂Bean本身。
对于FactoryBean是否有了基本的认识,但是不是会觉得这样做毫无意思啊,为什么要使用FactoryBean包裹一层呢?这样很麻烦啊
2. FactoryBean作用为什么需要使用FactoryBean呢?
-
考虑下,如果需要实例化一个复杂Bean,按照传统方式,我们需要在
中提供大量的配置信息,但这些信息还是我们不需要去关注的,我们只想要创建一个Bean,并不想知道这个Bean是经过多么复杂的流程创建出来的,这时就可以使用FactoryBean来把一些配置信息、依赖项进行封装在内部,很简单的来实例化一个Bean -
和第三方框架的整合,首先在第三方框架内部是不会出现像@Component这样的Spring注解,为什么呢?因为如果使用了@Component注解,是不是就要依赖Spring。第三方框架与Spring框架整合,就是需要将第三方框架中的类转化为BeanDefinition放到Spring容器中去,以注解或者XML形式都行。往往第三方类都有一个非常重要的类,我们只需要将这个类注入到Spring就可以了,不过这个类想要正常工作可能需要其他依赖,所以我们在Spring中想注入这个类,就需要先知道它依赖的其他类,可是其他类还会有依赖,这样做就太麻烦了,所以第三方框架可以写一个FactoryBean类,提供一个简单的入口和Spring框架进行整合,我们只需要将这个FactoryBean类以注解或XML的格式放到容器就可以了。(Mybatis集成入Spring就是这样)
我们在整合MyBatis与Spring时需要在XML中配置SqlSessionFactory
在SpringBoot项目中整合MyBatis,我们不需要进行过多的额外配置,只需要引入MyBatis包就可以直接使用,我们并没有配置SqlSessionFactory,但是我们没配并不代表没有,而是SpringBoot帮我们写了,在MybatisAutoConfiguration自动配置类中有如下一个@Bean注解:
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
// 此处就是用FactoryBean
// 使用SqlSessionFactoryBean来创建的SqlSessionFactory
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setVfs(SpringBootVFS.class);
if (StringUtils.hasText(this.properties.getConfigLocation())) {
factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
}
// 从this.properties中可以拿到在配置文件中 Mybatis 配置的信息
Configuration configuration = this.properties.getConfiguration();
if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {
configuration = new org.apache.ibatis.session.Configuration();
}
// ……
return factory.getObject();
}
说明:上面方法中,从this.properties属性中可以拿到在application.yaml或者是application.properties中Mybatis 配置的信息,配置如下
mybatis: mapper-locations: classpath:/mapper/** String beanName = transformedBeanName(name); Object bean; Object sharedInstance = getSingleton(beanName); // 此处拿到sharedInstance,不为空,表示已经实例化了,但属性有没有填充不确定 if (sharedInstance != null && args == null) { bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { // sharedInstance为null,才会进入到这里,表示从singletonObjects中拿不到 // 省略从单例池中获取不到时,开始创建bean的过程 } return (T) bean; }下面看下这行代码getSingleton(beanName),看下是如何拿从缓存中拿取Bean的,会执行到DefaultSingletonBeanRegistry类中的getSingleton()方法
protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 从singletonObjects中获取bean,如果不为空直接返回,不再进行初始化工作 Object singletonObject = this.singletonObjects.get(beanName); // isSingletonCurrentlyInCreation()方法判断当前beanName是不是正在创建中 // 如果为null并且正在创建中,则会进入 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { // 去earlySingletonObjects中拿,注意这行集合里面存放的对象还没有被填充属性 singletonObject = this.earlySingletonObjects.get(beanName); // 如果也没拿到,说明还没有创建完成 if (singletonObject == null && allowEarlyReference) { // 去存放Bean工厂的集合里拿,看看是不是Bean工厂 ObjectFactory> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; }在获取到sharedInstance不为空的时候,会进入下面这行代码bean = getObjectForBeanInstance(sharedInstance, name, beanName, null)进行进一步判断
protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, RootBeanDefinition mbd) { // name不为空并且name是以"&"开始,进if if (BeanFactoryUtils.isFactoryDereference(name)) { if (beanInstance instanceof NullBean) { return beanInstance; } // beanInstance不是FactoryBean,则抛异常 if (!(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass()); } } // 如果beanInstance不是FactoryBean(也就是普通bean),则直接返回beanInstance // 如果beanInstance是FactoryBean,并且name以“&”为前缀,则直接返回beanInstance(以“&”为前缀代表想获取的是FactoryBean本身) if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { return beanInstance; } // 走到这边,代表beanInstance是FactoryBean,但name不带有“&”前缀,表示想要获取的是FactoryBean创建的对象实例 Object object = null; if (mbd == null) { // 如果mbd为空,则尝试从factoryBeanObjectCache缓存中获取该FactoryBean创建的对象实例 object = getCachedObjectForFactoryBean(beanName); } if (object == null) { // 只有beanInstance是FactoryBean才能走到这边,因此直接强转 FactoryBean> factory = (FactoryBean>) beanInstance; if (mbd == null && containsBeanDefinition(beanName)) { // mbd为空,但是该bean的BeanDefinition在缓存中存在,则获取该bean的MergedBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); } // mbd是否是合成的(这个字段比较复杂,mbd正常情况都不是合成的,也就是false boolean synthetic = (mbd != null && mbd.isSynthetic()); // 从FactoryBean获取对象实例,这句是关键代码 object = getObjectFromFactoryBean(factory, beanName, !synthetic); } // 返回对象实例 return object; } @Nullable protected Object getCachedObjectForFactoryBean(String beanName) { // 可以看到就是从factoryBeanObjectCache里面取已经缓存的,这样第二次再去获取的时候不用再次创建 return this.factoryBeanObjectCache.get(beanName); }下面看一下FactoryBeanRegistrySupport类中的getObjectFromFactoryBean()方法:
protected Object getObjectFromFactoryBean(FactoryBean> factory, String beanName, boolean shouldPostProcess) { // 1.如果是单例,并且已经存在于单例对象缓存中,什么意思? // 就是说FactoryBean你可以在类上标注为多实例的bean,那么在多次获取FactoryBean的时候 // 实际就是多次调用FactoryBean的getObject方法,如果是单实例的,则进行缓存起来,只创建一次 if (factory.isSingleton() && containsSingleton(beanName)) { synchronized (getSingletonMutex()) { // 3.从FactoryBean创建的单例对象的缓存中获取该bean实例 //关于这个factoryBeanObjectCache上面我们已经介绍过了 Object object = this.factoryBeanObjectCache.get(beanName); if (object == null) { // 4.调用FactoryBean的getObject方法获取对象实例 object = doGetObjectFromFactoryBean(factory, beanName); Object alreadyThere = this.factoryBeanObjectCache.get(beanName); // 5.如果该beanName已经在缓存中存在,则将object替换成缓存中的 if (alreadyThere != null) { object = alreadyThere; } else { //6.判断需要做后置处理,shouldPostProcess传过来的是!synthetic,即为true,不是合成的 if (shouldPostProcess) { if (isSingletonCurrentlyInCreation(beanName)) { return object; } beforeSingletonCreation(beanName); try { // 7.对bean实例进行后置处理,执行所有已注册的BeanPostProcessor的postProcessAfterInitialization方法 //此方法会进行AOP代理增强,所以我们在写AOP增强的时候,不只是会增强FactoryBean本身,还会增强FactoryBean所包裹的对象 object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { // 抛异常略 } finally { afterSingletonCreation(beanName); } } if (containsSingleton(beanName)) { // 8.将beanName和object放到factoryBeanObjectCache缓存中 this.factoryBeanObjectCache.put(beanName, object); } } } // 9.返回object对象实例 return object; } } else { // 10.调用FactoryBean的getObject方法获取对象实例 //可以看出来,如果是多实例的,那么每次是直接创建的 Object object = doGetObjectFromFactoryBean(factory, beanName); if (shouldPostProcess) { try { // 11.对bean实例进行后置处理,执行所有已注册的BeanPostProcessor的postProcessAfterInitialization方法 object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { // 抛异常略 } } // 12.返回object对象实例 return object; } }上述代码中的4会调用FactoryBean的getObject()方法获取对象实例
上述代码中的7会对Bean实例进行后置处理
下面看下4中的doGetObjectFromFactoryBean()方法,位于FactoryBeanRegistrySupport类中,代码如下:
private Object doGetObjectFromFactoryBean(final FactoryBean> factory, final String beanName) { Object object; try { // 1.调用FactoryBean的getObject方法获取bean对象实例 if (System.getSecurityManager() != null) { AccessControlContext acc = getAccessControlContext(); try { // 1.1 带有权限验证的 object = AccessController.doPrivileged((PrivilegedExceptionAction上面的方法很简单,就是直接调用 FactoryBean的 getObject()方法来获取到对象实例。
上面代码中的7调用 FactoryBeanRegistrySupport类中的postProcessObjectFromFactoryBean()方法,此步骤主要是对Bean进行后置后置增强的。
@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; // 1.遍历所有注册的BeanPostProcessor实现类,调用postProcessAfterInitialization方法 for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { // 2.在bean初始化后,调用postProcessAfterInitialization方法 result = beanProcessor.postProcessAfterInitialization(result, beanName); if (result == null) { // 3.如果返回null,则不会调用后续的BeanPostProcessors return result; } } return result; }3. 小结在取FactoryBean包裹的对象时,也就是不加&符号的流程如下:
首先会对beanName名字进行转换,获取真正的beanName,然后根据beanName从singletonObjects中取出Bean实例,如果拿出来为null,则要进行创建步骤,如果不为空,接着判断这个Bean,如果不是FactoryBean类型的,或者名称中是以&开头,则直接返回取出的bean实例
为什么会直接返回呢?因为从singletonObjects中拿出来的Bean实例就是FactoryBean
如果是FactoryBean类型的,名称中不是以&开头,再判断是单实例还是多实例的,如果是多实例的,则直接调用FactoryBean的getObject()方法,如果单实例的,则先从factoryBeanObjectCache缓存中去拿,没有的话则进行创建
创建完成后,会判断这个FactoryBean的BeanDefinition是不是合成,如果不是,则执行BeanPostProcessor后置处理器的postProcessAfterInitialization进行增强,如果需要增强的话
FactoryBean包裹的对象是天然懒加载的,如果是单例的,则会在第一个调用getBean()的时候创建,然后放到缓存中



