FactoryBean就是生成Bean的, 其目的就是为了创建对象
FactoryBean 就是一个工厂Bean,相当于将工厂类放到了Spring中管理、当获取此Bean的时候返回的是此工厂生成的Bean。需要经过完整的一系列过程才可以创建出Bean
文章目录
- 1.测试
- 2.使用FactoryBean与 自己创建对象对比
- 3.FactoryBean 流程分析
- 4.总结
1.测试
public class Cat {
}
@Component
public class CatFactory implements FactoryBean<Cat> {
@Override
public Cat getObject() throws Exception {
return new Cat();
}
@Override
public Class getObjectType() {
return Cat.class;
}
}
@Configuration
@ComponentScan("com.zzz.a8")
public class MainConfig {
@Bean
public CatFactory catFactory(){
return new CatFactory();
}
}
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
Object bean = context.getBean("catFactory");
System.out.println(bean.getClass());
Object bean1 = context.getBean("&catFactory");
System.out.println(bean1.getClass());
}
}
当创建对象的过程复杂时可使用BeanFactory,调用方只需要注入就可使用
FactoryBean使创建对象操作 更加语义化
2.使用FactoryBean与 自己创建对象对比
既然factoryBean目的就是创建对象, 那如果我们自己写一个方法也可以完成同样的操作, 那为什么要使用factoryBean呢
使用方法创建对象
public class Cat {
}
@Component
public class CatFactory {
public Cat getCat(){
return new Cat();
}
}
public class Main {
@Autowired
private CatFactory catFactory;
public void main(String[] args) throws Exception{
Cat cat = catFactory.getCat();
}
}
总结:
- 对于调用方只需要知道对象即可, 不需要管生产方式, 符合迪米特法则, 知道的越少越好
- 通过FactoryBean创建对象与其他正常对象, 使用起来无差别
- 将操作复杂化, 全部封装到FactoryBean接口中, 使得类更具体化, 与Spring风格统一
- 但是, 单用这个类效果不大, 常常都是同时继承其他类, 实现其他接口协同
创建对象时需要依赖于 别的接口 监听数据,推送数据过来的接口 做一些数据处理时, 可以使用FactoryBean.
需要搭配其他接口协作, 依赖于Spring的某个生命周期内, 某个时间节点 来生成对象
3.FactoryBean 流程分析
DefaultListableBeanFactory.java
preInstantiateSingletons()
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(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);
}
}
}
else {
getBean(beanName);
}
}
}
FactoryBeanRegistrySupport
doGetObjectFromFactoryBean()
AbstractBeanFactory
getBean() -> doGetBean() -> getObjectForBeanInstance()
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.
// 容器已经得到了Bean实例对象(这个实例对象可能是一个普通的Bean,也可能是一个工厂Bean)
// 如果是一个工厂Bean,则使用它创建一个Bean实例对象,
// 如果调用本身就想获得一个容器的引用,则指定返回这个工厂Bean实例对象
// 如果指定的名称是容器的解引用(dereference,即是对象本身而非内存地址),且Bean实例也不是创建Bean实例对象的工厂Bean
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
// 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.
// 如果Bean实例不是工厂Bean,或者指定名称是容器的解引用,调用者向获取对容器的引用,则直接返回当前的Bean实例
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
// 处理指定名称不是容器的解引用,或者根据名称获取的Bean实例对象是一个工厂Bean
// 使用工厂Bean创建一个Bean的实例对象
Object object = null;
if (mbd == null) {
// 从Bean工厂缓存中获取给定名称的Bean实例对象
object = getCachedObjectForFactoryBean(beanName);
}
// 让Bean工厂生产给定名称的Bean对象实例
if (object == null) {
// Return bean instance from factory.
FactoryBean factory = (FactoryBean) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
// 如果从Bean工厂生产的Bean是单态模式的,则缓存
if (mbd == null && containsBeanDefinition(beanName)) {
// 从容器中获取指定名称的Bean定义,如果继承基类,则合并基类相关属性
mbd = getMergedLocalBeanDefinition(beanName);
}
// 如果从容器得到Bean定义信息,并且Bean定义信息不是虚构的,则让工厂Bean生产Bean实例对象
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 调用FactoryBeanRegistrySupport类的getObjectFromFactoryBean方法,实现工厂Bean生产Bean对象实例的过程
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
FactoryBeanRegistrySupport
getObjectFromFactoryBean() -> doGetObjectFromFactoryBean()
调用 Bean工厂的 getObject() 方法生产指定Bean的实例对象
private Object doGetObjectFromFactoryBean(FactoryBean factory, String beanName) throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
BeanFactory 接口调用其实现类的 getObject 方法来实现创建 Bean实例对象功能
4.总结
FactoryBean 的实现类有非常多,比如:Proxy、RMI、JNDI、ServletContextFactoryBean 等等。FactoryBean 接口为 Spring 容器提供了一个很好的封装机制,具体的 getObject()有不同的实现类根据不同的实现策略来具体提供。
- BeanFactory 是一个大工厂,是IOC容器的根基,有繁琐的 bean 生命周期处理过程,可以生成出各种各样的 Bean
- FactoryBean 是一个小工厂,它自己也是一个 Bean ,但是可以生成其他 Bean