FactoryBean
什么是FactoryBean
FactoryBean不是BeanFactory,它是一个特殊的Bean。
我们可以写自己的XXXBeanFactory来实现BeanFactory接口,并重写其中的方法:
package com.example.firstspringboot.service;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;
@Component
public class LangFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
return new Person();
}
@Override
public Class<?> getObjectType() {
return Person.class;
}
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
public class FirstSpringBootApplication {
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(FirstSpringBootApplication.class, args);
System.out.println(applicationContext.getBean("langFactoryBean"));
}
}
如上代码,当我们使用getBean方法来获取langFactoryBean时,得到的对象不是langFactoryBean,而是LangFactoryBean中重写的getObject()方法中返回的对象。
此外,并不是每次调用getBean方法,都调用一次getObject()方法,实际上getObject方法只会调用一次。
那么如果我们就是想取到langFactoryBean这个Bean,怎么办呢?
加上&
applicationContext.getBean("&langFactoryBean")
原理:
- 在doGetBean方法中调用了getObjectForBeanInstance方法:
```java
protected
T doGetBean(String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { …; beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null); …; }
2. 在getObjectForBeanInstance中调用了BeanFactoryUtils.isFactoryDereference(name), 判断是不是以`&`开头:
```java
protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
if (BeanFactoryUtils.isFactoryDereference(name)) {
...;
reutrn beanInstance;
}
}
public static boolean isFactoryDereference(@Nullable String name) {
return name != null && name.startsWith("&");
}
- 因此,以
&
开头就认为是个FactoryBean,getBean 的时候加了&
就直接返回这个FactoryBean。 如果是以
&
开头,但是不是一个FactoryBean(说明是普通Bean),那么也直接返回这个Bean(即便以&开头);else if (!(beanInstance instanceof FactoryBean)) { return beanInstance; }
否则,那就说明是一个FactoryBean,而且调用getBean的时候没有以
&
开头,就回去尝试从factoryBeanObjectCache中获取缓存的Bean,因为第一次调用的时候这个Bean并没有初始化,因此得到的是Null ```java object = this.getCachedObjectForFactoryBean(beanName);
protected Object getCachedObjectForFactoryBean(String beanName) { return this.factoryBeanObjectCache.get(beanName); }
6. 如果得到的是NULL, 就会去尝试调用BeanFactory中的getObject方法,创建这个Bean;
```java
if (object == null) {
...;
object = this.getObjectFromFactoryBean(factory, beanName, !synthetic);
}
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && this.containsSingleton(beanName)) {
...;
object = this.doGetObjectFromFactoryBean(factory, beanName);
}
}
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
if (System.getSecurityManager() != null) {
...;
} else {
object = factory.getObject();
}
}
- 拿到这个对象以后,放入到factoryBeanObjectCache缓存中去(不会放到单例池中):
if (this.containsSingleton(beanName)) { this.factoryBeanObjectCache.put(beanName, object); }
FactoryBean有什么用
可以用来集成第三方库,例如Mybatis。如果我们要将UserMapper注入到UserService里边去,因为UserMapper是个接口,所以需要注入的是UserMapper的代理对象,而且这个代理对象还需要是Spring中的一个Bean。
此时就可以通过FactoryBean来生成该UserMapper的代理对象。
BeanFactory和FactoryBean的区别
BeanFactory是整个Spring中最重要的东西,主要的职责就是创建各种各样的Bean。
FactoryBean是一种特殊的Bean,这个FactoryBean内部可以创建一个新的Bean。
GetBean
GetBean方法干了两件事:
- 获取Bean;
- 如果Bean不存在,去生成Bean;
获取Bean
GetBean调用doGetBean方法,实际操作都是在doGetBean中。
doGetBean方法首先去单例池里获取Bean, 如果找到了并不是直接返回这个Bean, 因为这个Bean可能是FactoryBean,因此要通过调用getObjectForBeanInstance方法来获得真正想要的Bean.
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
xxx;
Object sharedInstance = this.getSingleton(beanName);
if (sharedInstance != null && args == null) {
beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
}
}
getObjectForBeanInstance方法:
- 如果是普通Bean,返回普通Bean对象;
如果是FactoryBean
- 如果加了&开头,则返回FactoryBean对象;
否则返回FactoryBean中getObject方法里返回的对象。
protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { // 如果以&开头 if (BeanFactoryUtils.isFactoryDereference(name)) { // 如果是NullBean,直接返回 if (beanInstance instanceof NullBean) { return beanInstance; // 如果不是FactoryBean对象,抛出异常 } else if (!(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass()); // 说明确实是FactoryBean,因为加了&,所以就返回这个FactoryBean对象 } else { if (mbd != null) { mbd.isFactoryBean = true; } return beanInstance; } // 如果没有以&开头并且不是FactoryBean // 说明是普通Bean,返回这个BeanInstance } else if (!(beanInstance instanceof FactoryBean)) { return beanInstance; // 否则就是FactoryBean,并且没有以&开头 } else { Object object = null; if (mbd != null) { mbd.isFactoryBean = true; } else { // 尝试去FactoryBeanCache中获取getObject中返回的对象 object = this.getCachedObjectForFactoryBean(beanName); } // 如果该对象不存在,尝试通过FactoryBean中的getObject方法来获取对象。 if (object == null) { FactoryBean<?> factory = (FactoryBean)beanInstance; if (mbd == null && this.containsBeanDefinition(beanName)) { mbd = this.getMergedLocalBeanDefinition(beanName); } boolean synthetic = mbd != null && mbd.isSynthetic(); // 该方法就是去通过FactoryBean中的getObject方法来获取Bean object = this.getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; } }
如果在单例池中没有找到Bean,且本BeanFactory中找不到对应BeanName的BeanDefinition,但是该BeanFactory存在parentBeanFactory,就尝试去parentBeanFactory中去查找。
BeanFactory parentBeanFactory = this.getParentBeanFactory(); if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) { String nameToLookup = this.originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly); } if (args != null) { return parentBeanFactory.getBean(nameToLookup, args); } if (requiredType != null) { return parentBeanFactory.getBean(nameToLookup, requiredType); } return parentBeanFactory.getBean(nameToLookup); }
生成Bean
经过上述两个步骤以后,说明单例池中确实没有我们想要的Bean,FactoryBean缓存中也没有,parentBeanFactory中也没有,那就确实没有这个Bean。
因此我们要去生成Bean。
生成Bean之前,首先要去获得MergedBeanDefinition。
RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
然后先去生成那些依赖的Bean,如果发现有循环依赖需要抛出异常。
String[] dependsOn = mbd.getDependsOn();
String[] var12;
if (dependsOn != null) {
var12 = dependsOn;
int var13 = dependsOn.length;
for(int var14 = 0; var14 < var13; ++var14) {
String dep = var12[var14];
// 检查是否存在循环依赖
// 如果有循环依赖就要抛出异常
if (this.isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
this.registerDependentBean(dep, beanName);
try {
this.getBean(dep);
} catch (NoSuchBeanDefinitionException var31) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", var31);
}
}
}
在生成完了依赖的那些Bean以后,就尝试去生成自己的这个Bean了。根据不同Bean的Scope来进行不同的实例化过程(singleton, prototype, request,Session…)
以下生命周期将详细解释Bean的生成过程
加载类
首先根据mergedBeanDefinition和beanName来尝试加载类:
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
xxx;
Class<?> resolvedClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
xxx;
}
在进行mergedBeanDefinition的解析的过程中,里边有个属性是BeanClass,可能是字符串(类的全限定名com.lang.xxx),可能是一个解析好的Class对象。
如果已经是一个Class对象了,那么就直接返回:
protected Class<?> resolveBeanClass(RootBeanDefinition mbd, String beanName, Class<?>... typesToMatch) throws CannotLoadBeanClassException {
xxx;
if (mbd.hasBeanClass()) {
return mbd.getBeanClass();
}
xxx;
}
否则就调用doResolveBeanClass方法,获得类加载器,尝试去加载类。
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch) throws ClassNotFoundException {
ClassLoader beanClassLoader = this.getBeanClassLoader();
ClassLoader dynamicLoader = beanClassLoader;
xxx;
return mbd.resolveBeanClass(beanClassLoader);
}
↓
public Class<?> resolveBeanClass(@Nullable ClassLoader classLoader) throws ClassNotFoundException {
String className = this.getBeanClassName();
if (className == null) {
return null;
} else {
// 该方法就是在加载类
Class<?> resolvedClass = ClassUtils.forName(className, classLoader);
this.beanClass = resolvedClass;
return resolvedClass;
}
}
实例化 + 初始化
实例化过程分为实例化前->实例化->实例化后
实例化前和实例化后实际上都类似于钩子函数,例如在实例化前,程序员可以自己生成一个Bean对象,而不使用Spring默认的方法来生成Bean。然后直接进入
实例化前:
如果程序员自己生成了Bean对象,就不会让Spring采用默认方法去生成Bean对象了,然后就直接进入到初始化后阶段(注意不是实例化后阶段).
@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
xxx;
if (targetType != null) {
// 实例化前,如果我们自己返回了一个Bean
bean = this.applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
// 直接进入到初始化后阶段
bean = this.applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
xxx;
return bean;
}
实例化 > 初始化:
调用Spring默认的方法进行实例化:
实例化 -> 填充属性 (先执行实例化后,再填充属性) -> 执行aware方法 -> 初始化前 -> 初始化 -> 初始化后(AOP)
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
xxxx;
beanInstance = this.doCreateBean(beanName, mbdToUse, args);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
xxxx;
if (instanceWrapper == null) {
// 实例化
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}
xxx;
// 填充属性
// 事实上,先执行实例化后的钩子函数,再填充属性
this.populateBean(beanName, mbd, instanceWrapper);
// 先调用invokeAwareMethods方法
// 初始化前方法: applyBeanPostProcessorsBeforeInitialization
// 初始化:invokeInitMethods
// 初始化后:applyBeanPostProcessorsAfterInitialization
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
}