概述
在前面的学习当中,我们了解了spring的资源加载策略,知道了spring如何将资源封装为Resource并且利用ResourceLoader加载Resource资源,然后解析Resource资源,将其装换为保存在spring内部的元数据BeanDefinition。前面做的所有工作都是在为IOC容器开始Bean的加载所做的准备。
IOC容器的作用如上图所示,它通过加载元数据,然后将其解析到容器内部。然后根据这些信息绑定整个系统的对象,最终 组装成一个可用的基于轻量级容器的应用系统。 要想真正得到一个完整的IOC容器,需要两步:1.容器的初始化阶段和bean的加载阶段,而现在我们学习的内容就是针对于第二个阶段。
在Bean的加载阶段开始的时候,加载Bean所需要的全部的信息已经进入到系统中了。当我们显式或者隐式地调用 BeanFactory#getBean(…) 方法的时候,就会开启Bean的加载过程。
实例代码如下:
ResourceLoader resourceLoader = new DefaultResourceLoader();// <1>
//ClassPathResource resource = new ClassPathResource("bean.xml");
ClassPathResource resource = (ClassPathResource)resourceLoader.getResource("bean.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); // <2>
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); // <3>
reader.loadBeanDefinitions(resource); // <4>
Car car = (Car)factory.getBean("car");
System.out.println(car);
为了便于梳理整个加载过程,其时序图如下:
这里的时序图只是bean加载过程当中我认为比较重要的方法,具体的看代码分析。
总体流程分析
getBean
当我们显式或者隐式掉一共getBean方法的时候,就会触发架子啊Bean阶段。
@Override
public Object getBean(String name) throws BeansException {
//doGetBean接受4个方法参数:获取bean的名字,bean的类型
//创建bean式要传递的参数,是否类型检查。
return doGetBean(name, null, null, false);
}
真正实现加载机制的是doGetBean方法
doGetBean
这个方法就是上面时序图的体现。代码如下:
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
/**
* 通过name获取beanName,这里不使用name直接作为beanName有两个原因
* 1.name可能以&字符开头,表明调用者想获取FactoryBean本身,而不是FactoryBean实现类所创建的
* bean。在BeanFactory中,FactoryBean的实现类和其他的bean存储方式是一样的。区别在于名字上多了个&
* 所以要移除这个&
* 2.还是别名的问题,转换需要。
*/
//1.返回bean名称,剥离工厂使用前缀,如果那么是alias,就过去对应的映射的beanname
//如果是FactoryBean,要去除它前面的那个&
final String beanName = transformedBeanName(name);
//创建一个空的bean
Object bean;
// Eagerly check singleton cache for manually registered singletons.
//如果这里是我们的bean,那么第一次获取肯定是空的,那么这个时候就会走else
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//2.完成FactoryBean的相关处理,并用来获取FactoryBean的处理结果。
//缓存中的bean记录的是最原始的Bean状态,我们得到的不一定是最终想要的bean
//
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
//3.因为spring只支持解决单例模式下的循环依赖,所以原型模式下会抛出异常。
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
//4.如果容器中没有找到就从父类容器中加载
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
//验证方法注入
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
//5.如果不是仅仅做类型检查则是创建bean,这里需要记录
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
//6.从容器中获取beanname对应的 GenericBeanDefinition 对象,
// 并将其转换为 RootBeanDefinition 对象,转换的原因是RootBeanDefinition是子类
//它提供了更多的方法供之后使用
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//检查给定的合并的BeanDefinition
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
//7.处理所依赖的bean
if (dependsOn != null) {
for (String dep : dependsOn) {
//若给定的依赖bean已经注册为依赖给定的bean
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
//缓存依赖调用.......
registerDependentBean(dep, beanName);
try {
//递归处理依赖bean
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
//8.bean实例化
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
//这里才开始正式创建
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
//显式从单例池中删除Bean实例
//因为单例模式下为了解决循环依赖,可能它已经存在了.....
// 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);
}
//原型模式下创建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 = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
//从指定的scope下创建bean
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 = 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);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
//9.检查需要的类型是否符合bean的实际类型
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
在这个代码中IOC完成了Bean的加载。同时循环依赖的解决也是在这个代码中完成的。由于这个代码很长,可以根据执行的顺序一步一步学习。
- 首先处理Beanname,这个name的处理主要解决两个问题,1.将FactoryBean的名字的前缀去掉2.将别名改为真正的名字
- 然后第一次通过getSingleton从单例池或者缓存中获取实例。缓存是解决循环依赖使用的,之后会讲。如果获取到了调用getObjectForBeanInstance进行FactoryBean的处理。
- 大部分的代码如上所示,之后的学习中主要围绕这个代码学习
处理Beanname
transformedBeanName这个方法是doGetBean方法中最开始需要执行的逻辑
// AbstractBeanFactory.java
final String beanName = transformedBeanName(name);
protected String transformedBeanName(String name) {
//canonicalName取指定的alias所比表示的最终的beanname
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
String beanName = name;
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
return beanName;
}
//SimpleAliasRegistry.java
public String canonicalName(String name) {
String canonicalName = name;
// Handle aliasing...
String resolvedName;
do {
//到记录别名的map中去一个一个比较。
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
- transformedBeanName的主要作用是去除name的修饰符,name可能以&字符开头,表明调用者想获取FactoryBean本身,而不是FactoryBean实现类所创建的 bean。在BeanFactory中,FactoryBean的实现类和其他的bean存储方式是一样的。区别在于名字上多了个&
- canonicalName进行别名的转换
总而言之,在transformedBeanName方法中对传入的name进行了处理,方便下面进行操作。
FactoryBean简介
我觉得这个知识点值得单独学习,所以这里就是简单概括一下。
一般来说spring利用反射机制来注入我们配置的bean的属性。但是如果我们在配置bean的时候,有很多的配置项,那么利用反射来注入就会比较复杂。所以Spring提供了 org.Springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化bean的逻辑。
package org.Springframework.beans.factory; public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType(); boolean isSingleton();
}
比如一个实例:
public class CarFactoryBean implements FactoryBean<Car> {
private String carInfo;
public Car getObject() throws Exception {
Car car = new Car();
String[] infos = carInfo.split(",");
car.setBrand(infos[0]);
car.setMaxSpeed(Integer.valueOf(infos[1]));
car.setPrice(Double.valueOf(infos[2])); return car;
}
public Class<Car> getObjectType() {
return Car.class;
}
public boolean isSingleton() {
return false;
}
}