我们先看一道面试经常会问到的问题:spring的bean在什么时候实例化? ——第一:如果你使用BeanFactory,如XmlBeanFactory作为Spring Bean的工厂类,则所有的bean都是在第一次使用该bean的时候实例化 。第二:如果你使用ApplicationContext作为Spring Bean的工厂类,则又分为以下几种情况:
1.如果bean的scope是singleton的,并且lazy-init为false(默认是false,所以可以不用设置),则ApplicationContext启动的时候就实例化该bean,并且将实例化的bean放在一个线程安全的 ConcurrentHashMap 结构的缓存中,下次再使用该Bean的时候,直接从这个缓存中取 。
2.如果bean的scope是singleton的,并且lazy-init为true,则该bean的实例化是在第一次使用该bean的时候进行实例化 。
3.如果bean的scope是prototype的,则该bean的实例化是在第一次使用该Bean的时候进行实例化 。
ClassPathXmlApplicationContext有几个重载的构造函数最终都会调用父类AbstractApplicationContext的reflash方法,reflash方法在前文有介绍,作用是创建加载Spring容器配置。AbstractApplicationContext也有getBean方法:
AbstractApplicationContext下的代码:
public Object getBean(String name)throws BeansException {
//Bean的获取外部容器交给了内部容器
return getBeanFactory().getBean(name);
}
内部容器由DefaultListableBeanFactory承当,但真实的getBean方法实现是由其父类AbstractBeanFactory实现的,AbstractBeanFactory类同样实现了BeanFactory接口的方法,它有四个重载的getBean方法,不管哪一个都会去调用doGetBean方法:
那么doGetBean里干了什么事情呢?
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)throws BeansException {
//bean name处理,去除FactoryBean前缀等
final String beanName = transformedBeanName(name);
Object bean = null;
//先从singleton缓存中查看是否已经实例化过该Bean,根据是否有缓存分为两个分支分别处理
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
// 分支一,若缓存中获取到了并且该BeanDefinition信息表明该bean是singleton的,直接将获取到的缓存Bean
//(有可能是半成品)交给getObjectForBeanInstance处理
/*.........省略logger部分代码............*/
//调用getObjectForBeanInstance处理
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}else {
// 分之二:没有缓存,则需要从头实例化该bean
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);}
// 检查BeanDefinition是否在当前工厂或父工厂
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (args != null) {
// 父工厂getBean
return parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
//将bean加入“正在创建”的集合,完成后会remove,对应afterSingletonCreation/afterPrototypeCreation方法
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 解决依赖关系,将依赖的bean提前实例化
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (int i = 0; i < dependsOn.length; i++) {
String dependsOnBean = dependsOn[i];
getBean(dependsOnBean);
registerDependentBean(dependsOnBean, beanName);
}
}
// 这里又需要根据bean的类型分为三种情况:singleton、prototype、request/session
if (mbd.isSingleton()) {
//通过自定义ObjectFactory实例化Bean,此结果可能是半成品(是FactoryBean等)
sharedInstance = getSingleton(beanName, new ObjectFactory() {
public Object getObject()throws BeansException {
try {
//真正实例化装配的逻辑在createBean方法中
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
}
});
//上一步半成品的Bean交给getObjectForBeanInstance方法处理
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
//真正实例化装配的逻辑在createBean方法中
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
//上一步半成品的Bean交给getObjectForBeanInstance方法处理
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
//request、session 的bean
String scopeName = mbd.getScope();
final Scope scope = (Scope) this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory() {
public Object getObject()throws BeansException {
beforePrototypeCreation(beanName);
try {
//真正实例化装配的逻辑在createBean方法中
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
//上一步半成品的Bean交给getObjectForBeanInstance方法处理
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; " +
"consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
if (requiredType != null && bean != null &&
!requiredType.isAssignableFrom(bean.getClass())) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return bean;
}
bean的加载经历了一个复杂的过程,上面代码主要做了以下几件事(此段摘抄自《spring源码深度解析》):
1.转换对应的beanName。如果name=“&aa”的,会去除&符号。或者<bean>标签带有alias(别名的意思),则取alias所表示最终的beanName。
2.尝试从缓存中加载单例bean。如果加载不成功,会再次尝试从singletonFactories中加载。
3.bean的实例化。假如我们需要对工厂bean进行处理,那么这里得到的其实是工厂bean 的初始状态。真正干活的则是getObjectForBeanInstance定义factory-method方法返回的bean。
4.原型模式的依赖检查。如果A类有B的属性,B中有A的属性,则会产生循环依赖。spring如何解决循环依赖问题
5.将存储的Xml配置文件的GernericBeanDefinition转换为RootBeanDefinition。前文提到的用于承载属性的BeanDefinition有三个实现,GernericBeanDefinition,RootBeanDefinition和ChildBeanDefinition,如果父类bean不为空的话,这里会把所有的属性一并合并父类属性,因为后续所有的Bean都是针对RootBeanDefinition的。
6.寻找依赖。在初始化一个bean的时候,会首先初始化这个bean所对应的依赖。
7.根据不同的scope创建bean。scope属性默认是singleton,还有prototype、request等。
8.类型转换。如果bean是个String,而requiredType传入了Integer,然后返回bean,加载结束。
其中,最重要的步骤是(7),spring的常用特性都在那里实现.