一、目的
spring管理的bean实例分为两类,一类是实现FactoryBean接口的Bean,一类是其它类型的Bean。getObjectForBeanInstance目的是为了从FactoryBean类型的bean实例中获取正确的bean。
二、FactoryBean的使用方法
一般类型的bean实例化时,spring通过反射机制利用bean标签中的class属性来实例化一个bean,然后利用bean标签中配置的property子节点,来设置bean对象的属性值。这种方式在创建bean有复杂的逻辑时,就显得略微乏力。下面看一下FactoryBean的功能。
- 实现FactoryBean接口的实体类
@Data
public class MyFactoryBean implements FactoryBean<Person> {
private String personInfo;
@Override
public Person getObject() throws Exception {
// 该方法内可以编写较为复杂的创建逻辑...
Person person = new Person();
person.setName("factoryBean");
person.setNickName(personInfo);
return person;
}
@Override
public Class<?> getObjectType() {
return Person.class;
}
}
- 在applicationContext.xml中配置bean属性
<bean id="myPersonFactoryBean" class="com.kaka.spring.pojo.MyFactoryBean">
<property name="personInfo" value="test factory bean"/>
</bean>
- 从spring工厂中获取bean
@Test
public void getObjectForBeanInstance(){
Resource classPathResource = new ClassPathResource("applicationContext.xml");
BeanFactory xmlBeanFactory = new XmlBeanFactory(classPathResource);
// 获取的beanName为bean标签中的id时,返回的bean为MyFactoryBean的getObject()方法的返回值
Person myPerson = xmlBeanFactory.getBean("myPersonFactoryBean", Person.class);
System.out.println(myPerson);
// 获取的beanName为bean标签中的id前加上&时,返回的bean为MyFactoryBean本身
MyFactoryBean myFactoryBean = xmlBeanFactory.getBean("&myPersonFactoryBean", MyFactoryBean.class);
System.out.println(myFactoryBean);
}
三、bean加载流程
- 获取用户传入name对应的beanName
- 尝试从缓存中获取bean实例
- 缓存中不存在,根据找到对应的BeanDefinition信息,加载bean实例
- 从bean实例中获取真正的对象(本节解析)
- 转换对象类型
- 返回对象实例
四、相关类及方法
- org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean:加载一个Bean的整体过程都在这个方法中
- org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance
- org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean
- org.springframework.beans.factory.support.FactoryBeanRegistrySupport#doGetObjectFromFactoryBean
五、源码分析
1. 先看加载bean的方法,AbstractBeanFactory#doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 1.转换beanName,主要处理别名、以&开头的name
final String beanName = transformedBeanName(name);
Object bean;
// 2.尝试从单例缓存中获取bean实例
Object sharedInstance = getSingleton(beanName);
// 3. 获取bean实例
// 3.1 缓存中已存在bean实例
if (sharedInstance != null && args == null) {
// 省略日志输出代码...
// 从bean实例中获取对象(本章重点,获取实例中的对象)
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 省略父工厂处理相关代码...
try {
// 省略dependsOn相关代码...
// 3.2 创建单例bean
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
// 从bean实例中获取对象(本章重点,获取实例中的对象)
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 3.3 创建原型bean实例
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
// 从bean实例中获取对象(本章重点,获取实例中的对象)
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 3.4 根据scope创建bean实例
else {
String scopeName = mbd.getScope();
final 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, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
// 从bean实例中获取对象(本章重点,获取实例中的对象)
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
// 省略异常处理代码...
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// 省略其他代码.
...
}
可以看到上面有四种情况:缓存中存在bean实例、创建单例bean、创建原型bean、根据scope创建bean,都调用了getObjectForBeanInstance()方法,接下来我们就点进去看看。
2. 从bean实例的初始状态获取对象
name以&开头,称为工厂引用。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 1. 如果是工厂引用(即name以&开头),但该实例又不是FactoryBean类型,则抛出异常
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
}
// 2. 如果该实例不是FactoryBean类型,或者是工厂引用都直接返回该实例
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
// 尝试从缓存中加载bean
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// 把初始bean实例强转为FactoryBean
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
// 是否是用户自定义的beanDefinition(默认是false)
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 重点方法,跟进去
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
从上面的代码还看不出从FactoryBean中获取对象的代码,继续看getObjectFromFactoryBean()方法
3. 从FactoryBean中获取对象:getObjectFromFactoryBean()
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
// 1. 单例模式
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 真正获取对象的方法(重点方法)
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)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
beforeSingletonCreation(beanName);
try {
// 调用bean的后置处理器(有兴趣的可以点进去看下,后面的章节会单独讲述)
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
// 2. 原型模式
// 真正获取对象的方法(重点方法)
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
无论是单例还是原型的bean实例,都会调用doGetObjectFromFactoryBean()方法进行真正的获取逻辑,跟进去看看
4. 真正从FactoryBean中获取对象的逻辑:doGetObjectFromFactoryBean()
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
// 权限验证
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
// 终于看到你了!
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
最终发现其实获取对象的方法,就是一行调用FactoryBean的getObject()方法。
六、借鉴
- spring中方法调用层级
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
// 省略其他无关代码...
object = doGetObjectFromFactoryBean(factory, beanName);
}
对于某个功能中涉及到许多辅助类的逻辑(缓存、前后置处理等)时,可以把这些辅助类逻辑放到功能方法中;把真正的功能逻辑抽取到doXxx()方法里面。