【Spring源码研究】- BeanFactory与FactoryBean

1.BeanFactory

BeanFactory 是一个接口,提供了 IOC 容器的最基本的形式, Spring 中 IOC 容器有很多,如:AbstractApplicationContext,DefaultListableBeanFactory等,其本身的职责是:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖,由于其只是一个接口,所以只是定义了一些 IOC 的规范,而具体的实现是实现了 BeanFactory 接口的子类去做的处理,从 BeanFactory 本身的含义来看,表示的是一个生产 Bean 的工厂,通过反射将 Bean 的定义信息具体化为相应的对象(创建对象)。

2.FactoryBean

FactoryBean 本身也是一个接口,从字面意思来看,这是一个Bean,一个工厂Bean,既然是个工厂Bean,那么便可以生产或者修饰对象

这类似于工厂模式和装饰器模式。

FactoryBean 源码如下

public interface FactoryBean<T> {

	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

    /**
    * 这个方法极为重要: 此方法就是我们自定义对象实现的地方
    */
	@Nullable
	T getObject() throws Exception;

	@Nullable
	Class<?> getObjectType();
    
	default boolean isSingleton() {
		return true;
	}
}

从上面可以看到这个接口有三个方法,一个变量;

变量:

String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

可以设置在 BeanDefinition 上的属性的名称,以便在工厂 bean 类中无法推断时可以返回一个默认的类型。(描述不太准确,没找到相关案例)

方法:getObject()

@Nullable
T getObject() throws Exception;

从工厂中获取一个 bean 的实例,

如果一个类 A 实现了 FactoryBean 接口,那么 A 将变成一个工厂,此时通过调用 getObject() 方法返回的是 getObject() 方法中创建的实例,而不是返回工厂实例,当然如果你想要得到工厂实例可以在名称前加一个"&"符号就可以得到。

方法:getObjectType()

@Nullable
Class<?> getObjectType();

返回类 A 中通过 getObject() 方法创建的对象的类型,我查看了大多数 FactoryBean 接口的实现类,都实现了 getObject() 方法 以及 getObjectType() 方法,然后基本上 在 getObjectType() 方法中返回的类型都是 getObject() 方法中创建的对象的类型,当然,你要是想玩点骚的,也可以在 getObjectType() 方法中返回其他类型。

我自己做了一个小实验,自己写了一个类 TestFactoryBean 实现了 FactoryBean 接口,但是我在 getObjectType() 方法中返回的对象类型并不是 getObject() 方法中创建的对象的类型,但是也能拿到。当然不推荐这么做,毕竟搞开发没必要搞些别人无法理解的操作, 本人就是好奇的试了一下。

示例代码如下:

一个会被创建对象的类:User

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Integer age;
    private String name;
}

一个实现了 FactoryBean 接口的类:TestFactoryBean

@Component
public class TestFactoryBean implements FactoryBean {
    public Object getObject() throws Exception {
        return new User(18, "法外狂徒张三");
    }
    public Class<?> getObjectType() {
        return List.class;
    }
}

一个用来查看结果的类:Test

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.refresh();
        context.register(TestFactoryBean.class);
        //获取的是 getObject() 方法创建的对象
        User user = (User) context.getBean("testFactoryBean");
        System.out.println(user);
        //获取的是 TestFactoryBean 类型的对象
        TestFactoryBean factory = (TestFactoryBean) context.getBean("&testFactoryBean");
        System.out.println(factory.getObjectType());
    }
}

结果:

User(age=18, name=法外狂徒张三)
interface java.util.List

结果中的第一行输出了由 TestFactoryBean 类的 getObject() 方法创建的 User 类的对象

结果中的第二行输出了由 TestFactoryBean 类的 getObjectType() 方法返回的 List 接口的类型,包含类型(interface)与包名(java.util.List)

对于这个方法的用法我知道的有限,以后有新的发现在继续补充。 //TODO

方法:isSingleton()

default boolean isSingleton() {
	return true;
}

判断当前工厂管理的对象是否是单例的,如上面的例子可以判断 factory 对象是否是单例的,由于 factory 对象对应的类实现了FactoryBean 接口,故可以调用 isSingleton() 方法来判断本身是否是单例对象。

FactoryBean 本身的单例状态通常由拥有此 FactoryBean 的 BeanFactory 提供;通常,它必须定义为单例。这里这样说是因为 FactoryBean 本身就是一个特殊的 Bean,也是由 BeanFactory 进行管理。

3.区别与联系

区别:

BeanFactory 就是一个实例化 Bean 的一个工厂;而 FactoryBean 就是一个特殊的 Bean,是由 BeanFactory 进行管理的;实现了FactoryBean 接口的类有能力改变 Bean ,FactoryBean 希望你实现了它之后返回一些内容,Spring会按照这些内容去注册 Bean.

联系:

在某种意义上其实 FactoryBean 也可以理解为一个工厂,一个用来生产特殊的 Bean 的工厂,有一种场景是,我们使用一个通用的类来在xml 文件中注册 Bean A,我们希望通过该通用 Bean A产生一个我们希望的 Bean B,而这个需求 FactoryBean 就可以办到,你只需要拦截你需要代理的 Bean A,然后转换成你希望的 Bean B再注册就可以的到我们想要的 Bean 。一个应用场景就是 RPC 服务器端的 Bean 注册,以及 RPC 客户端的服务调用,都可以通过一个第三方 Bean 来产生我们真正需要的 Bean 。这里生产 Bean B 的过程就像是在使用工厂创建 Bean ,只不过创建的逻辑是由我们自定义的。这里可以参考 Spring 的 Feign 接口调用源码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值