FactoryBean
先来介绍一下FactoryBean是什么。以及BeanFactory和FactoryBean的区别。
举个栗子:
MyFactoryBean.class
public class MyFactoryBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User("zhangsan");;
}
@Override
public Class<?> getObjectType() {
return User.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
User.class
public class User {
private String name;
public User() {}
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
新建一个factoryBean.xml,将我们创建的MyFactoryBean
交由Spring进行管理。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.springframework.custom.MyFactoryBean" id="userFactoryBean">
</bean>
</beans>
main
准备工作都已经做完,接下来我们看看在Spring中如何创建的User对象。
public static void main(String[] args) {
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("factoryBean.xml");
User u = ac.getBean("userFactoryBean",User.class);
System.out.println(u.getName());
}
加载
我们先来看这样几个问题,并带着问题这么几个问题来阅读源码。
- 上面xml中< bean >标签的class属性值是MyFactoryBean的全限定名,为什么main方法中通过getBean()可以获取到User对象。
- main方法走完,当使用FactoryBean创建对象的时候,创建了几个?
- 创建的对象是否由Spring进行管理。
我们先回到preInstantiateSingletons
方法,看看mergeBeanDefinition
后都干了什么。
preInstantiateSingletons
merge后,进行了类型判断、如果当前BeanDefinition不是抽象类、并且是单例、并且不是懒加载,则会进入到下一个 if 判断中。
而我们当前beanDefinition为上文中创建的 MyFactoryBean, 所以理所当然的属于FactoryBean。
而我们想要获取到User对象,必然要先得到 MyFactoryBean 对象。
所以经过 getBean -> doGetBean -> createBean -> doCreateBean 的一系列操作后,返回的Object bean 是 MyFactoryBean。
public void preInstantiateSingletons() throws BeansException {
//获取所有beanDefinitionName
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
//合并父类beanDefinition
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//如果不是抽象类,并且是单例,并且不是懒加载
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
//是否实现了FactoryBean接口
if (isFactoryBean(beanName)) {
//根据 &+beanName获取具体实例对象
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
}
// 省略部分代码....
}
}
}
}
可以看到我们当前的beanName是创建的userFactoryBean
,而BeanFactory
中的singletonObject
缓存中也已经有以userFactoryBean为key的缓存,此时通过该key 可以获取到 MyFactoryBean实例。
但是整个流程走完,会发现只有MyBeanFactory
对象的创建,并没有我们的User对象,而我们上面的demo代码中可以清晰的看到,想要获取User对象,要调用 getObject()
方法,上面的流程中并没有。接下来让我们回到 main 方法的入口。
getObject
这次我们从main方法中的 ac.getBean
入口进入,看看都干了什么。
依然是getBean -> doGetBean -> createBean -> doCreateBean的流程。
public static void main(String[] args) {
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("factoryBean.xml");
User u = ac.getBean("userFactoryBean",User.class);
System.out.println(u.getName());
}
getBean -> doGetBean
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
doGetBean
截取部分源码。 当前的 mbd 依然是我们自定义的MyFactoryBean
。
// Create bean instance.
//bean的范围是 SINGLETON 或者 DEFAULT
if (mbd.isSingleton()) {
//从缓存中获取实例bean
sharedInstance = getSingleton(beanName, () -> {
try {
//创建bean
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 如果 bean的范围是 PROTOTYPE
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
//如果是 PROTOTYPE,则创建一个新实例
Object prototypeInstance = null;
try {
//使用 ThreadLocal 作为缓存
beforePrototypeCreation(beanName);
//创建实例
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
//创建完实例后,将beanName从ThreadLocal中移除
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
//如果scopeName 为 null 则抛出异常。
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
//使用 ThreadLocal 作为缓存
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
//创建完实例后,将beanName从ThreadLocal中移除
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
}
并且代码中无论走哪个 if else 的分支,都会通过 createBean() —》 doCreateBean()
方法进行实例的创建,但这时创建出来的实例也依然是 myFactoryBean
。
此时我们想要的User.class
还是没创建,但是别急,我们在接着往下看看 createBean() 过后的 getObjectForBeanInstance
getObjectForBeanInstance
方法主要是做一些判断并设置标志位mbd.isFactoryBean = true;
,方法的最后会调用getObjectFromFactoryBean
。
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不是工厂,不要让调用代码尝试取消对工厂的引用
// 如果name为FactoryBean的解引用.name是以'&'开头,就是FactoryBean的解引用
if (BeanFactoryUtils.isFactoryDereference(name)) {
//如果beanInstance是NullBean,则直接返回beanInstance
if (beanInstance instanceof NullBean) {
return beanInstance;
}
//如果beanInstance不是FactoryBean,则抛出异常
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
//如果beanInstance是FactoryBean,则设置mbd.isFactoryBean为true
if (mbd != null) {
mbd.isFactoryBean = true;
}
//返回beanInstance
return beanInstance;
}
// 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.
// 如果beanInstance是FactoryBean,则使用它来创建一个bean实例,除非调用者实际上想要一个对工厂的引用。
//如果不是,则返回beanInstance
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
Object object = null;
//如果mbd不为空,则设置mbd.isFactoryBean为true
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
//如果mbd为空,则从缓存中获取beanInstance
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
//将beanInstance强转成FactoryBean
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
//缓存从FactoryBean获得的对象,如果它是单例的。
//如果当前BeanDefinition为null && 当前beanFactory的beanDefinitionMap中包含当前beanName的BeanDefinition
if (mbd == null && containsBeanDefinition(beanName)) {
//获取beanName合并后的本地RootBeanDefintiond对象
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
//从FactoryBean中获取bean
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
getObjectFromFactoryBean
从FacrotyBean中获取Bean实例。
从factoryBeanObjectCache
缓存中尝试获取,获取不到则调用doGetObjectFromFactoryBean
方法创建实例Bean,并放到factoryBeanObjectCache
缓存中。
需要注意的是,我是要通过自定义的MyFactoryBean
创建User.class,所以此时的beanName 依然是 xml中配置的 bean标签的id userFactoryBean。factory也是创建好的实例 MyFactoryBean
。
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
//是否是单例 && 缓存中是否包含该对象
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
//从factoryBeanObjectCache缓存中获取
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
//调用FactoryBean的getObject方法获取对象
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
// 仅在上面的getObject()调用期间进行后处理和存储(如果尚未放置)
// (例如,由于自定义getBean调用触发的循环引用处理)
// 重新从factoryBeanObjectCache中获取beanName对应bean对象
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
//如果alreadyThere != null
//让object 引用 alreadyThere
if (alreadyThere != null) {
object = alreadyThere;
}
else {
//如果要进行后处理
if (shouldPostProcess) {
//如果是单例对象正在创建中
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
// 暂时返回非后处理对象,不存储它,直接返回object
return object;
}
// 创建单例之前的回调
beforeSingletonCreation(beanName);
try {
// 对从FactoryBean获得的给定对象进行后处理.
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
// 建单例之后的回调
afterSingletonCreation(beanName);
}
}
// 如果singletonObjects缓存中存在该beanName
if (containsSingleton(beanName)) {
//放入factoryBeanObjectCache缓存中
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
//当前factory不是单例 || singletonObjects缓存中不包含该beanName
//调用FactoryBean的getObject方法获取对象
Object object = doGetObjectFromFactoryBean(factory, beanName);
//如果要进行后处理
if (shouldPostProcess) {
try {
// 对从FactoryBean获得的给定对象进行后处理.
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
doGetObjectFromFactoryBean
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
Object object;
try {
//如果有安全管理器
if (System.getSecurityManager() != null) {
// 忽略...
}
else {
//通过调用getObject()方法获取Bean实例
object = factory.getObject();
}
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
//不接受不完全的FactoryBean的空值,
if (object == null) {
// 如果 beanName当前正在创建(在整个工厂内)
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
// 让object引用一个新的NullBean实例
object = new NullBean();
}
return object;
}
可以看到,此时方法返回的Object对象就是我们想要的User对象。
顺着getObjectFromFactoryBean
方法继续向下走,直到return object时我们再通过debug查看当前容器(BeanFactory)中的singletonObjects
缓存,发现里面依然没有我们创建的 User 对象,不过factoryBeanObjectCache
缓存中却多了一个 key = userFactoryBean
的值。
但是!!! 虽然两个缓存中的key相同,但指向的却是两个对象 singletonObjects 中是 MyFactoryBean
而factoryBeanObjectCache中指向的是User对象
。
总结
回到文章开始我们提出的三个问题,随着对源码的了解,问题的答案也渐渐清晰:
- 上面xml中< bean >标签的class属性值是MyFactoryBean的全限定名,为什么main方法中通过getBean()可以获取到User对象。
1.1 首先创建MyFactoryBean的实例,并通过getObject()创建User对象并返回。 - main方法走完,当使用FactoryBean创建对象的时候,创建了几个?
2.1 2个对象,1个MyFactoryBean对象 1个User对象 - 创建的对象是否由Spring进行管理。
3.1 会由Spring进行管理么? 我们再次debug查看一下。
main
我们稍微修改一下main方法,看此时u1 u2是否相等。
public static void main(String[] args) {
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("factoryBean.xml");
User u1 = ac.getBean("userFactoryBean",User.class);
User u2 = ac.getBean("userFactoryBean",User.class);
System.out.println(u1 == u2);
}
源码中有提到,当我们第一次创建User对象后,会放入factoryBeanObjectCache
缓存中,所以当u2进行加载时,会直接从factoryBeanObjectCache
缓存获取。
getCachedObjectForFactoryBean
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
//省略部分源码。。。
Object object = null;
//如果mbd不为空,则设置mbd.isFactoryBean为true
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
//如果mbd为空,则从缓存中获取beanInstance
object = getCachedObjectForFactoryBean(beanName);
}
// 省略部分源码
return object;
}
protected Object getCachedObjectForFactoryBean(String beanName) {
return this.factoryBeanObjectCache.get(beanName);
}
当u2进来时,factoryBeanObjectCache
缓存不为null,从缓存中取值后直接 return。
还记得MyFactory类中的isSingleton()
方法么?当时我们是默认给的true,现在我们改成false再看看u1 u2还是否相等。
public class MyFactoryBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User("zhangsan");
}
@Override
public Class<?> getObjectType() {
return User.class;
}
@Override
public boolean isSingleton() {
return false;
}
}
再次debug会发现,factoryBeanObjectCache
缓存为null,当u2调用getBean()方法时,还是会再走一遍之前的创建流程。
所以对于问题3的答案:
如果实现的isSingleton()
方法返回是true,则创建的对象会放入,factoryBeanObjectCache
缓存中交由Spring进行管理,如果isSingleton()
方法返回的是false,则每次都会创建新对象。不会交给Spring进行管理。