Spring之FactoryBean

FactoryBean

一、官方说明

Interface to be implemented by objects used within a BeanFactory which are themselves factories for individual objects. If a bean implements this interface, it is used as a factory for an object to expose, not directly as a bean instance that will be exposed itself.

由BeanFactory中使用的对象实现的接口,这些对象本身就是单个对象的工厂。如果一个bean实现了这个接口,它将被用作一个要公开的对象的工厂,而不是直接作为一个将要公开的bean实例。

也就是说,FactoryBean本身是一个Bean,但是却是不公开,换句话说,就是不经常使用这个bean,而是使用这个工厂对象产生bean。

NB: A bean that implements this interface cannot be used as a normal bean. A FactoryBean is defined in a bean style, but the object exposed for bean references (getObject()) is always the object that it creates.

一个bean实现了FactoryBean接口,不能够做为一个正常的bean。使用FactoryBean可以来定义bean的风格,但是这个bean对象是FactoryBean调用getObject()方法创建出来的对象。

FactoryBeans can support singletons and prototypes, and can either create objects lazily on demand or eagerly on startup. The SmartFactoryBean interface allows for exposing more fine-grained behavioral metadata

FactoryBean可以支持单例和原型bean,并且可以根据需要或在启动时提前创建bean对象。SmartFactoryBean接口允许公开更细粒度的行为元数据

This interface is heavily used within the framework itself, for example for the AOP org.springframework.aop.framework.ProxyFactoryBean or the org.springframework.jndi.JndiObjectFactoryBean. It can be used for custom components as well; however, this is only common for infrastructure code.

该接口在框架本身中大量使用,例如AOP org.springframework.AOP.framework.ProxyFactoryBean或org.springfframework.jndi.JndiObjectFactoryBean。它也可以用于自定义组件;然而,这仅适用于基础结构代码。

The container is only responsible for managing the lifecycle of the FactoryBean instance, not the lifecycle of the objects created by the FactoryBean. Therefore, a destroy method on an exposed bean object (such as java.io.Closeable.close() will not be called automatically. Instead, a FactoryBean should implement DisposableBean and delegate any such close call to the underlying object.

容器只负责管理FactoryBean实例的生命周期,而不是FactoryBean创建的对象的生命周期。因此,不会自动调用公开的bean对象(例如java.io.Closable.close())上的destroy方法。相反,FactoryBean应该实现DisposableBean并将任何此类关闭调用委托给基础对象。

二、FactoryBean组织结构

/**
 * 实现此接口的bean不能用作普通bean。此bean暴露的对象是通过getObject()创建的对象,而不是它自身
 */
public interface FactoryBean<T> {
    /**
     * 返回此工厂管理的对象的实例(可能是共享的或独立的,取决于isSingleton()的返回值)
     */
    @Nullable
    T getObject() throws Exception;
  
    /**
     * 返回此FactoryBean创建的对象类型,
     */
    @Nullable
    Class<?> getObjectType();
  
    /**
     * 该工厂管理的对象是否为单例?
     * 如果是(return true),getObject()总是返回同一个共享的实例,该对象会被BeanFactory缓存起来
     * 如果是(return false),getObject()返回独立的实例
     * 一般情况下返回true
     */
    default boolean isSingleton() {
        return true;
    }
}

说的简单点,FactoryBean是BeanFactory支持的、用来暴露bean实例的接口。

三、FactoryBean使用

public class Car {}
@Component
public class MyFactoryBean implements FactoryBean<Car> {
  @Override
  public Car getObject() throws Exception {
    return new Car();
  }
  
  @Override
  public Class<?> getObjectType() {
    return Car.class;
  }
}

测试类:

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(LiAppCOnfig.class);
applicationContext.refresh();
System.out.println(applicationContext.getBean("myFactoryBean").getClass().getSimpleName());
System.out.println(applicationContext.getBean("&myFactoryBean").getClass().getSimpleName());

打印输出结果:

Car
MyFactoryBean

通过正常的myFactoryBean(beanName)获取得到的是FactoryBean中产生的对象;而通过&myFactoryBean(&beanName)获取得到的是FactoryBean当前类的对象。

四、源码分析

通过源码进行分析

applicationContext.getBean("myFactoryBean")

一开始从spring容器获取名为myFactoryBean的bean,类型确实是:MyFactoryBean,但是后面又经过getObjectForBeanInstance来真正获取我们需要的对象

看下具体的源码:

然后调用具体的方法

那么这里就有一个细节问题:FactoryBean调用getObject()方法产生的对象只走了后置处理方法,没有走初始化前、初始化方法,而是直接走了初始化后方法。

4.1、制造场景

public class Car implements InitializingBean {
	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("初始化方法");
	}
}

调用测试方法检测,发现控制台打印输出的是:

Car
MyFactoryBean

并没有执行对应的afterPropertiesSet初始化方法。

从这里也证明了,FactoryBean调用getObject()方法产生的对象并不是一个Spring真正意义上的Bean

posted @ 2023-02-15 11:09  写的代码很烂  阅读(183)  评论(0编辑  收藏  举报