Skip to content

FactoryBean

FactoryBean 接口的应用

说明

  1. FactoryBean 中的 getObject() 会返回你要使用的 UserFactoryEntity 实例。
  2. 从 BeanFactory 中获取 UserFactoryEntity 实例:context.getBean("demoFactoryBean");
  3. 从 BeanFactory 中获取 DemoFactoryBean 实例:context.getBean("&demoFactoryBean");

可以看出:

  1. 如果要获取原始的 FactoryBean 对象,需要在 beanName 前添加前缀 ”&“,这样 Spring 才会把他识别为要获取一个 FactoryBean 类型的对象。
  2. 虽然 UserFactoryEntity 没有被 Spring 容器扫描为一个 bean(类上面没有添加 @Component 注解),但由于写了 DemoFactoryBean,于是 Spring 容器根据这个 FactoryBean 实例化了 UserFactoryEntity 对象,并且添加到了 Spring 容器中。
java
@Data
public class UserFactoryEntity {
    private String name;
}

定义 FactoryBean 的实现类

java
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;
@Component
public class DemoFactoryBean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        // 用户可以自定义这个实例的属性和对象本身如何生成
        UserFactoryEntity bean = new UserFactoryEntity();
        bean.setName("Jack");
        return bean;
    }
    @Override
    public Class<?> getObjectType() {
        return UserFactoryEntity.class;
    }
}

测试

java
import lombok.SneakyThrows;
import org.junit.jupiter.api.Assertions;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication(scanBasePackages = "com.github.mengweijin.mybatisplus.demo.FactoryBean")
public class FactoryBeanTest {

    @SneakyThrows
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(FactoryBeanTest.class, args);
        String beanName = "demoFactoryBean";

        Object entityObject = context.getBean(beanName);
        Assertions.assertNotNull(entityObject);
        Assertions.assertTrue(entityObject instanceof UserFactoryEntity);

        Object factoryBeanObject = context.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
        Assertions.assertNotNull(factoryBeanObject);
        Assertions.assertTrue(factoryBeanObject instanceof DemoFactoryBean);

        DemoFactoryBean bean = context.getBean(DemoFactoryBean.class);
        Object object = bean.getObject();
        Assertions.assertTrue(object instanceof UserFactoryEntity);
        UserFactoryEntity entity = (UserFactoryEntity) object;
        Assertions.assertEquals("Jack", entity.getName());

        context.close();
    }
}

源码解读

FactoryBean 类型的类的实例化

Spring 核心方法中的 finishBeanFactoryInitialization(beanFactory);

├─finishBeanFactoryInitialization(beanFactory);
│ └─beanFactory.preInstantiateSingletons();
│ │ └─if (isFactoryBean(beanName))      在这个 if 里面实例化了实现了 FactoryBean 接口的类。

代码

java
if (isFactoryBean(beanName)) {
    // 这里就可以看出,实例化 FactoryBean 本身的类 beanName 添加了前缀 ”&“
    Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
    if (bean instanceof FactoryBean) {
        FactoryBean<?> factory = (FactoryBean<?>) bean;
        boolean isEagerInit;
        if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
            isEagerInit = AccessController.doPrivileged(
                (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
                getAccessControlContext());
        }
        else {
            isEagerInit = (factory instanceof SmartFactoryBean &&
                ((SmartFactoryBean<?>) factory).isEagerInit());
        }
        if (isEagerInit) {
            getBean(beanName);
        }
    }
}

FactoryBean.getObject()

上面的代码只是实例化了 FactoryBean 本身,只有调用了 FactoryBean.getObject() 才会得到我们想要的 bean 对象。 那么 FactoryBean.getObject() 是在哪儿被调用的呢?

├─finishBeanFactoryInitialization(beanFactory);
│ ├─beanFactory.preInstantiateSingletons();
│ │ ├─getBean(beanName);
│ │ │ ├─doGetBean(name, null, null, false);
│ │ │ │ ├─if (mbd.isSingleton()) {
│ │ │ │ │ ├─在一般的 bean 实例化完成后,接着实例化实现了 FactoryBean 接口的 factory.getObject() 的实例。
│ │ │ │ │ ├─beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
│ │ │ │ │ │ ├─object = getObjectFromFactoryBean(factory, beanName, !synthetic);
│ │ │ │ │ │ │ ├─object = doGetObjectFromFactoryBean(factory, beanName);
│ │ │ │ │ │ │ │ ├─object = factory.getObject();

在上面的方法层级中的 getObjectFromFactoryBean 方法中,先从 factoryBeanObjectCache 缓存中获取 bean, 如果没有的话,在下面的 doGetObjectFromFactoryBean 方法中调用了 FactoryBean.getObject() 方法。