FactoryBean
FactoryBean 接口的应用
说明
- FactoryBean 中的 getObject() 会返回你要使用的 UserFactoryEntity 实例。
- 从 BeanFactory 中获取 UserFactoryEntity 实例:context.getBean("demoFactoryBean");
- 从 BeanFactory 中获取 DemoFactoryBean 实例:context.getBean("&demoFactoryBean");
可以看出:
- 如果要获取原始的 FactoryBean 对象,需要在 beanName 前添加前缀 ”&“,这样 Spring 才会把他识别为要获取一个 FactoryBean 类型的对象。
- 虽然 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() 方法。