BeanFactory和FactoryBean

1、 BeanFactory

BeanFactory定义了 IOC 容器的最基本形式,并提供了 IOC 容器应遵守的的最基本的接口,也就是 Spring IOC 所遵守的最底层和最基本的编程规范。

在 Spring 代码中, BeanFactory 只是个接口,并不是 IOC 容器的具体实现,但是 Spring 容器给出了很多种实现,如 DefaultListableBeanFactory 、 XmlBeanFactory 、 ApplicationContext 等,都是附加了某种功能的实现。

2、 FactoryBean

一般情况下,Spring 通过反射机制的方式实现类实例化 Bean ,如:bean标签、@Component、@Bean。

但是在某些情况下,实例化 Bean 过程比较复杂,如果按照传统的方式,则需要在 中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。 Spring 为此提供了一个FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化 Bean 的逻辑。

FactoryBean就是一个Bean,FactoryBean接口的地位很重要, Spring 自身就提供了 70 多个 FactoryBean 的实现。它们隐藏了实例化一些复杂 Bean 的细节,给上层应用带来了便利。能生产或者修饰对象生成的工厂 Bean.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface FactoryBean<T> {
//返回由 FactoryBean 创建的 Bean 实例,如果 isSingleton() 返回 true ,则该实例会放到 Spring 容器中单实例缓存池中
@Nullable
T getObject() throws Exception;

//返回 FactoryBean 创建的 Bean 类型。
@Nullable
Class<?> getObjectType();

//返回由 FactoryBean 创建的 Bean 实例的作用域是 singleton 还是 prototype
default boolean isSingleton() {
return true;
}

}

如果一个类实现了,那么在spring中就会有两个对象,一个是getObject()返回的对象,一个是当前实现FactoryBean的对象。getBean() 方法返回的不是 FactoryBean 本身,而是 FactoryBean#getObject() 方法所返回的对象,相当于 FactoryBean#getObject() 代理了 getBean() 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class User {
public void print(){
System.out.println("User");
}
}

@Component("mybean")
public class MyBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User();
}

@Override
public Class<?> getObjectType() {
return User.class;
}

@Override
public boolean isSingleton() {
return true;
}

public void print(){
System.out.println("MyBean");
}
}

@Configuration
@ComponentScan("org.hu.factorybean")
public class AppConfig {

}

public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
//就是getObject()返回的对象
User user = (User)applicationContext.getBean("mybean");
user.print();//输出User
//当前实现FactoryBean的对象要加个符号才能获取到
MyBean myBean = (MyBean) applicationContext.getBean("&mybean");
myBean.print();//输出MyBean
}
}

使用场景

FactoryBean在Spring中最为典型的一个应用就是用来创建AOP的代理对象。

如Mybatis-spring 中的 sqlSessionFactroyBean.

我们知道AOP实际上是Spring在运行时创建了一个代理对象,也就是说这个对象,是我们在运行时创建的,而不是一开始就定义好的,这很符合工厂方法模式。更形象地说,AOP代理对象通过Java的反射机制,在运行时创建了一个代理对象,在代理对象的目标方法中根据业务要求织入了相应的方法。这个对象在Spring中就是——ProxyFactoryBean。