spring源码:bean加载之从bean实例中获取对象(getObjectForBeanInstance)

一、目的

  spring管理的bean实例分为两类,一类是实现FactoryBean接口的Bean,一类是其它类型的Bean。getObjectForBeanInstance目的是为了从FactoryBean类型的bean实例中获取正确的bean。

二、FactoryBean的使用方法

一般类型的bean实例化时,spring通过反射机制利用bean标签中的class属性来实例化一个bean,然后利用bean标签中配置的property子节点,来设置bean对象的属性值。这种方式在创建bean有复杂的逻辑时,就显得略微乏力。下面看一下FactoryBean的功能。

  1. 实现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;
	}
}
  1. 在applicationContext.xml中配置bean属性
<bean id="myPersonFactoryBean" class="com.kaka.spring.pojo.MyFactoryBean">
    <property name="personInfo" value="test factory bean"/>
</bean>
  1. 从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加载流程

  1. 获取用户传入name对应的beanName
  2. 尝试从缓存中获取bean实例
  3. 缓存中不存在,根据找到对应的BeanDefinition信息,加载bean实例
  4. 从bean实例中获取真正的对象(本节解析)
  5. 转换对象类型
  6. 返回对象实例

四、相关类及方法

  • 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()方法里面。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值