Java

区别

BeanFactoryFactoryBean有哪些区别?」

  1. BeanFactory是一个最基础的IOC容器,提供了依赖查找,依赖注入等基础的功能
  2. FactoryBean是创建Bean的一种方式,帮助实现复杂Bean的创建

BeanFactory相关的还有一个高频的面试题

「ApplicationContext和BeanFactory有哪些区别?」

  1. BeanFactory是一个最基础的IOC容器,提供了依赖查找,依赖注入等基础的功能
  2. ApplicationContext继承了BeanFactory,在BeanFactory的基础上增加了企业级的功能,如AOP,资源管理(Resources)事件(Event),国际化(i18n),Environment抽象等

    创建Bean的方式

    常见的创建Bean的方式有如下四种

  3. 通过构造器

  4. 通过静态工厂方法
  5. 通过Bean工厂方法
  6. 通过FactoryBean ```java @Data @ToString public class User {

    private Long id; private String name;

    public static User createUser() {

    1. User user = new User();
    2. user.setId(1L);
    3. user.setName("li");
    4. return user;

    } }

public class UserFactory {

  1. public User createUser() {
  2. return User.createUser();
  3. }

}

public class UserFactoryBean implements FactoryBean {

  1. @Override
  2. public Object getObject() throws Exception {
  3. return User.createUser();
  4. }
  5. @Override
  6. public Class<?> getObjectType() {
  7. return User.class;
  8. }

}

  1. ```xml
  2. <?xml version="1.0" encoding="UTF-8"?>
  3. <beans xmlns="http://www.springframework.org/schema/beans"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. https://www.springframework.org/schema/beans/spring-beans.xsd">
  7. <!-- 构造方法实例化 Bean -->
  8. <bean id="user-by-constructor" class="com.javashitang.domain.User">
  9. <property name="id" value="1"/>
  10. <property name="name" value="li"/>
  11. </bean>
  12. <!-- 静态方法实例化 Bean -->
  13. <bean id="user-by-static-method" class="com.javashitang.domain.User"
  14. factory-method="createUser"/>
  15. <bean id="userFactory" class="com.javashitang.factory.UserFactory"/>
  16. <!-- Bean工厂方法实例化 Bean -->
  17. <bean id="user-by-factory" factory-bean="userFactory" factory-method="createUser"/>
  18. <!-- FactoryBean实例化 Bean -->
  19. <bean id="user-by-factory-bean" class="com.javashitang.factory.UserFactoryBean"/>
  20. </beans>
  1. public class BeanInstantiationDemo {
  2. public static void main(String[] args) {
  3. BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/bean-instantiation-context.xml");
  4. User user1 = beanFactory.getBean("user-by-constructor", User.class);
  5. User user2 = beanFactory.getBean("user-by-static-method", User.class);
  6. User user3 = beanFactory.getBean("user-by-factory", User.class);
  7. User user4 = beanFactory.getBean("user-by-factory-bean", User.class);
  8. }
  9. }

实现原理

在分析源码之前,先明确2个概念
factoryBean是配置到容器中的实现FactoryBean接口的Bean,而subBean是用FactoryBean创建出来的Bean」
在Spring容器启动的过程中,会实例化非延迟的单例Bean,即调用如下方法 DefaultListableBeanFactory#preInstantiateSingletons
2021-05-13-13-28-33-170878.png
调用FactoryBean#getObject的链路如下图
2021-05-13-13-28-33-297539.png
通过分析DefaultListableBeanFactory#preInstantiateSingletons方法和FactoryBean#getObject的调用链路可以分析得到

  1. 单例的factoryBean对象本身会在Spring容器启动时主动初始化。而subBean的初始化则是在第一次从缓存中获取factoryBean并且不为空才会触发
  2. 如果factoryBean对象实现的接口是SmartFactoryBeanisEagerInit方法返回true,那么subBean对象也会在Spring容器启动的时候主动初始化
  3. 如果bean注册的时候,beanName对应的bean实例是一个factoryBean,那么通过getBean(beanName)获取到的对象将会是subBean对象;如果要获取工厂对象factoryBean,需要使用getBean("&" + beanName)
  4. 单例的subBean也会缓存在Spring容器中,具体的容器是FactoryBeanRegistrySupport#factoryBeanObjectCache,一个Map<beanName, subBean实例>

「建议大家看一下DefaultListableBeanFactory#preInstantiateSingletons方法和FactoryBean#getObject方法的调用链路,就能理解上面的流程了」

应用

目前在Dubbbo源码中看到了FactoryBean的应用
「服务导出:在Dubbo中,服务提供者会被包装成ServiceBean对象,当监听到ContextRefreshedEvent事件时开始服务导出」
「服务调用:服务调用方会被包装成ReferenceBean对象,ReferenceBean实现了FactoryBean接口和InitializingBean接口,创建subBean的逻辑在ReferenceBean#getObject方法中」
「Dubbo服务引入的时机有如下2种。」

  1. 饿汉式:init=true,在Bean生命周期的初始化阶段会调用InitializingBean#afterPropertiesSet方法,而这个方法会调用ReferenceBean#getObject方法,完成subBean的创建,即ReferenceBean实例化时完成服务引入
  2. 懒汉式:init=false,在ReferenceBean对应的服务被注入到其他类中时,此时会调用AbstractApplicationContext#getBean,获取ReferenceBean对象,因为ReferenceBean实现了FactoryBean接口,所以会调用ReferenceBean#getObject方法,完成subBean的创建,即完成服务引入 ```java public class ReferenceBean extends ReferenceConfig implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean {

    @Override public Object getObject() {

    1. return get();

    }

    @Override @SuppressWarnings({“unchecked”}) public void afterPropertiesSet() throws Exception {

    1. // 省略部分代码
    2. if (shouldInit()) {
    3. getObject();
    4. }

    }

} ```