原型Bean加载进程
之前的文章,阐明白非懒加载的单例Bean整个加载进程,除了非懒加载的单例Bean之外,Spring中尚有一种Bean就是原型(Prototype)的Bean,软件开发,看一下界说方法:
<?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-3.0.xsd">
<bean id="prototypeBean" class="org.xrq.action.PrototypeBean" scope="prototype" />
</beans>
原型Bean加载流程总得来说和单例Bean差不多,看一下差异之处,在AbstractBeanFactory的doGetBean的要领的这一步:
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 = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
第6行createBean是一样的,原型Bean实例化的主要区别就在于第6行,它是直接建设bean的,而单例bean我们再比拟一下:
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory() {
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
它优先会实验getSington,即先实验从singletonObjects中获取一下bean是否存在,假如存在直接返回singletonObjects中的bean工具。
接着,我们看到原型bean建设和单例bean建设的区别还在于第5行和第9行,先看第5行的代码:
protected void beforePrototypeCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
if (curVal == null) {
this.prototypesCurrentlyInCreation.set(beanName);
}
else if (curVal instanceof String) {
Set<String> beanNameSet = new HashSet<String>(2);
beanNameSet.add((String) curVal);
beanNameSet.add(beanName);
this.prototypesCurrentlyInCreation.set(beanNameSet);
}
else {
Set<String> beanNameSet = (Set<String>) curVal;
beanNameSet.add(beanName);
}
}
这段主要是说bean在建设前要把当前beanName配置到ThreadLocal中去,其目标是担保多线程不会同时建设同一个bean。接着看第9行的代码实现,即bean建设之后做了什么:
protected void afterPrototypeCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
if (curVal instanceof String) {
this.prototypesCurrentlyInCreation.remove();
}
else if (curVal instanceof Set) {
Set<String> beanNameSet = (Set<String>) curVal;
beanNameSet.remove(beanName);
if (beanNameSet.isEmpty()) {
this.prototypesCurrentlyInCreation.remove();
}
}
}
很好领略,就是把当前bean移除一下,这样其它线程就可以建设bean了。第11行的代码不看了,意思是假如bean是FactoryBean的实现类的话,挪用getObject()要领获取真正的工具。
byName源码实现
Spring有为开拓者提供Autowire(自动装配)的成果,自动装配最常用的就是byName和byType这两种属性。由于自动装配是为了办理工具注入导致的<property>过多的问题,因此很容易找到byName与byType的Spring源码实现应该在属性注入这一块,定位到属性注入的代码AbstractAutowireCapableBeanFactory的populateBean要领,直接截取重点:
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}