Spring的BeanFactory和FactoryBean

官方定义

  • BeanFactory:Spring Bean容器的根接口
  • FactoryBean:各个对象的工厂接口,如果bean实现了这个接口,它将被用作对象的工厂,而不是直接作为bean实例。

源码解析

BeanFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface BeanFactory {
//标注是获取FactoryBean的实现类,而不是调用getObject()获取的实例
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
boolean containsBean(String name);
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
String[] getAliases(String name);
}

从源码的方法定义上,就可以看出,BeanFactory作为bean的容器管理器,提供了一系列获取bean以及获取bean属性的方法。

写一个小例子试验下:

SimpleBean:

1
2
3
4
5
public class SimpleBean {
public void send() {
System.out.println("Hello Spring Bean!");
}
}

Spring配置文件config.xml:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="simpleBean" class="base.SimpleBeanFactoryBean"/>
</beans>

测试方法:

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
public static void main(String[] args) throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
BeanFactory beanFactory = context.getAutowireCapableBeanFactory();
System.out.println("通过名称获取bean");
SimpleBean simpleBean = (SimpleBean) beanFactory.getBean("simpleBean");
simpleBean.send();
System.out.println("通过名称和类型获取bean");
simpleBean = beanFactory.getBean("simpleBean", SimpleBean.class);
simpleBean.send();
System.out.println("通过类型获取bean");
simpleBean = beanFactory.getBean(SimpleBean.class);
simpleBean.send();
boolean containsBean = beanFactory.containsBean("simpleBean");
System.out.println("是否包含 simpleBean ? " + containsBean);
boolean singleton = beanFactory.isSingleton("simpleBean");
System.out.println("是否是单例? " + singleton);
boolean match = beanFactory.isTypeMatch("simpleBean", ResolvableType.forClass(SimpleBean.class));
System.out.println("是否是SimpleBean类型 ? " + match);
match = beanFactory.isTypeMatch("simpleBean", SimpleBean.class);
System.out.println("是否是SimpleBean类型 ? " + match);
Class<?> aClass = beanFactory.getType("simpleBean");
System.out.println("simpleBean 的类型是 " + aClass.getName());
String[] aliases = beanFactory.getAliases("simpleBean");
System.out.println("simpleBean 的别名 : " + Arrays.toString(aliases));
}

控制台结果:

1
2
3
4
5
6
7
8
9
10
11
12
通过名称获取bean
Hello Spring Bean!
通过名称和类型获取bean
Hello Spring Bean!
通过类型获取bean
Hello Spring Bean!
是否包含 simpleBean ? true
是否是单例? true
是否是SimpleBean类型 ? true
是否是SimpleBean类型 ? true
simpleBean 的类型是 base.SimpleBean
simpleBean 的别名 : []

FactoryBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public interface FactoryBean<T> {

/**
* 获取一个bean,如果配置了工厂bean,在getBean的时候,将会调用此方法,获取一个bean
*/
T getObject() throws Exception;

/**
* 获取bean的类型
*/
Class<?> getObjectType();

/**
* 是否是单例
*/
boolean isSingleton();

}

接口是泛型,定义了三个方法,其中getObject()是工厂模式的体现,将会通过此方法返回一个bean的实例。

一个小例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class SimpleBeanFactoryBean implements FactoryBean<SimpleBean> {
@Override
public SimpleBean getObject() throws Exception {
System.out.println("MyFactoryBean getObject");
return new SimpleBean();
}

@Override
public Class<?> getObjectType() {
System.out.println("MyFactoryBean getObjectType");
return SimpleBean.class;
}

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

以上可以修改为单例模式,可以做成线程安全的单例,可塑性较高。

配置文件config.xml:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="simple" class="base.SimpleBeanFactoryBean"/>
</beans>

注意,我们在这里只配置了SimpleBeanFactoryBean,并没有配置SimpleBean,接下来看下getBean方法的输出。

1
2
3
ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
SimpleBean simpleBean = context.getBean(SimpleBean.class);
simpleBean.send();

控制台输出:

1
2
3
MyFactoryBean getObjectType
MyFactoryBean getObject
Hello Spring Bean!

由此我们可以看出FactoryBean的执行流程

  1. 通过getObjectType获取bean的类型
  2. 调用getObject方法获取bean的实例

总结

BeanFactoryFactoryBean其实没有关系,只是名称比较像而已。

  • BeanFactory是IOC最基本的容器,负责生产和管理bean,它为其他具体的IOC容器提供了最基本的规范。
  • FactoryBean是一个接口,当在IOC容器中的Bean实现了FactoryBean后,通过getBean(String BeanName)获取到的Bean对象并不是FactoryBean的实现类对象,而是这个实现类中的getObject()方法返回的对象。要想获取FactoryBean的实现类,就要getBean(&BeanName),在BeanName之前加上&。
0%