从Spring源码看创建对象的过程

从Spring源码看创建对象的过程

Spring对于程序员set注入的属性叫做属性的填充、对于set注入之后的处理(包括BeanPostProcessor的处理、初始化方法的处理)叫做初始化。

研读AbstractBeanFactory类中的doGetBean()方法

doGetBean()方法首先完成的工作是获取对象(针对于 scope=singleton 这种形式的对象,Spring把曾经创建获得对象进行存储。后续先获取对象),如果获取不到,才会创建对象。

源码图如下:

粗略看创建对象的大体流程

从代码中,我们可以看到一行注释:

Create bean instance.

从Spring源码看创建对象的过程_第1张图片

这是通过scope进行讨论,以单例情况为例:

  1. 调用AbstractAutowireCapableBeanFactory类中的

    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)方法
    

    从Spring源码看创建对象的过程_第2张图片

  2. createBean方法又会调用本类中的doCreateBean方法;

  3. doCreateBean方法中createBeanInstance就是使用反射进行对象的创建;

    从Spring源码看创建对象的过程_第3张图片

  4. populateBean来完成属性填充

    属性的填充

    包括set注入
    和自动注入
        
  5. initializeBean方法进行初始化操作。

    初始化操作

详细阅读doGetBean方法

首先来看一下两个参数

protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException
name就是bean的id值;
requiredType指创建bean的类型;

代码详解:

final String beanName = transformedBeanName(name);
大多数情况下name和beanName是一样的,就是bean的id值;
但是还有两种情况,需要转换;
    1.实现FactoryBean接口类bean的id;
    比如 beanFactory.getBean("&s") 会把&去掉,剩下s;此时name为&s,beanName被赋值为了s
    2.如果配置文件bean为
    beanFactory.getBean("u"),通过别名u来获取bean,会转换成id。
Object bean;
代表最终创建好的对象
Object sharedInstance = getSingleton(beanName);
会从DefaultSingletonBeanRegistry 类中的 singletonObjects、earlySingletonObjects 、singletonFactories获取(从这三个中获取,是为了解决循环引用的问题);
	
1.第一次获取,会获取为null;
2.后续从Spring容器获取,可以获取到:
注意:Spring创建对象对象会有2种状态
    1 完全状态: 对象创建完成 属性填充完成 初始化完成 (如果需要代理 AOP,也已经完成)  
    2 正在创建中: 仅仅有一个简单对象

doGetBean中调用的DefaultSingletonBeanRegistry中getSingleton方法定义如下:

从Spring源码看创建对象的过程_第4张图片

if(sharedInstance != null && args == null) {
    if(logger.isTraceEnabled()) {
        if(isSingletonCurrentlyInCreation(beanName)) {——————————判断获取到的bean是否在创建中
            logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
        } else {
            logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
        }
    }————————这些代码是帮Spring开发人员作代码跟踪的
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}

bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);分析

sharedInstance是从getSingleton()方法中获取到的对象,它与返回的bean有什么区别,就是这行代码的主要功能。

applicationContext.xml配置文件中
如果bean的配置为:
 
那么获取到的sharedInstance 就等同于 bean;

如果bean的配置为:
 
此时获取到的sharedInstance是XXXFactoryBean类的对象,我们想获取的是XXXFactoryBean的getObject()里的对象,此时getObjectForBeanInstance(sharedInstance, name, beanName, null)返回返回 FactoryBean#getObject();

所以:
getObjectForBeanInstance(sharedInstance, name, beanName, null);
如果是简单对象 bean就是sharedInstance 
如果是FactoryBean对象 bean是 FactoryBean#getObject()返回的对象
if(isPrototypeCurrentlyInCreation(beanName)) {
    throw new BeanCurrentlyInCreationException(beanName);
}
用来校验:如果已经在创建这个bean了,抛出异常
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 if(requiredType != null) {
        // No args -> delegate to standard getBean method.
        return parentBeanFactory.getBean(nameToLookup, requiredType);
    } else {
        return(T) parentBeanFactory.getBean(nameToLookup);
    }
}
======doGetBean源码结束
用来解决Spring的父子容器问题:
    父子容器代码演示
 
    //applicationContext-parents.xml中有配置bean,
    
    applicationContext.xml中有配置bean
    
    @Test
    public void test3() {
        DefaultListableBeanFactory parent = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(parent);
        xmlBeanDefinitionReader.loadBeanDefinitions(new ClassPathResource("applicationContext-parents.xml"));
        DefaultListableBeanFactory child = new DefaultListableBeanFactory(parent);//把父容器传进来,作联系
        XmlBeanDefinitionReader xmlBeanDefinitionReader1 = new XmlBeanDefinitionReader(child);
        xmlBeanDefinitionReader1.loadBeanDefinitions(new ClassPathResource("applicationContext.xml"));
        //一旦使用父子容器 最终父子容器的配置信息 融合
        // 如果遇到同名的配置内容 使用子容器中的内容
        User u = (User) child.getBean("u");
        System.out.println("u = " + u);
        Product p = child.getBean("p", Product.class);
        System.out.println("p = " + p);
    }
    注意:如果子容器和父容器有相同类的注入,并且id也相同,会用子容器里的配置。
	如果有父容器有bean的配置信息,在子容器中没有,那么实例化父容器对应的bean(递归进行)
if(!typeCheckOnly) {
    markBeanAsCreated(beanName);
}

    typeCheckOnly是doGetBean()方法的参数,在调用getBean时,设置的值为false;
    typeCheckOnly 标志 false 【默认】
    typeCheckOnly=true代表 spring只是对获取类型进行判断而并不是创建对象
    beanFactory.getBean("u",User.class)
    typeCheckOnly = true:spring是不会创建User对象 判断当前工厂获得或者创建的对象类型是不是User类型
    typeCheckOnly=false:spring会创建对象 或者 获得这个对象 返回给调用者


	markBeanAsCreated(beanName);标志这个bean时需要常见对象,而不是进行类型检查;
	他需要做两件事:
		1. 标记这个bean被创建
		2. clearMergedBeanDefinition(beanName);

markBeanAsCreated(beanName)源码:

从Spring源码看创建对象的过程_第5张图片

要想理解markBeanAsCreated中的clearMergedBeanDefinition()概念,要继续往后看doGetBean()源码。
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

Spring中bean是有继承关系的。
————如果一个bean abstract被设置为true,那它就是专门被用来继承的抽象bean,作为父bean
————parent="p" 指定其继承于哪个bean。
进行汇总 汇总成了 RootBeanDefinition

Spring这样设计,是为了将共有的东西进行抽取到父bean中。
mergedBeanDefinition是指父子bean的定义整合到一起——————汇总成RootBeanDefinition。


这样就可以回答上面的问题了:markBeanAsCreated()中要标记它被创建完成,就意味着它合并过了,所以要进行clearMergedBeanDefinition()操作。
checkMergedBeanDefinition(mbd, beanName, args);
防止工厂中bean都是抽象bean。

从Spring源码看创建对象的过程_第6张图片

String[] dependsOn = mbd.getDependsOn();
if(dependsOn != null) {
    for(String dep: dependsOn) {
        if(isDependent(beanName, dep)) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
        }
        registerDependentBean(dep, beanName);
        try {
            getBean(dep);
        } catch(NoSuchBeanDefinitionException ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
        }
    }
}

这是为了处理depends-on的(现在已经很少在开发中使用了)
 

下面就是根据scope进行区分,来创建了:

我们开发中经常使用的是Singleton的scope,所以重点分析它。

if(mbd.isSingleton()) {
    sharedInstance = getSingleton(beanName, () - > {
        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);
}

这是要给lambda表达式:

首先调用getSingleton()方法
getSingleton()方法内部会调用createBean(beanName, mbd, args)方法(这是核心)

getSingleton()方法具体分析

从Spring源码看创建对象的过程_第7张图片

beforeSingletonCreation(beanName)方法分析

从Spring源码看创建对象的过程_第8张图片

用来做校验,需要满足如下两个条件:
1.这个bean没有被排除
	备注:排除的概念,比如@ComponentScan(excludeFilters=)
		比如
				
			
		用来排除某些bean
2.这个bean此时正在创建中
	如果在bean是被创建中的状态,就没必要再创建了,直接在缓存中获取就可以了,这是为了解决循环依赖问题的。

createBean()方法分析

从Spring源码看创建对象的过程_第9张图片

从Spring源码看创建对象的过程_第10张图片

研读doCreateBean()中创建对象的方法

从Spring源码看创建对象的过程_第11张图片

为什么对返回的是instanceWrapper(bean的包装)呢?

从Spring源码看创建对象的过程_第12张图片

为什么要封装属性呢?便于进行类型转换;

id是Integer类型
比如标签中设置 
"1"会通过类型转换器转为Integer类型
或者用@PropertySource()中@Value()注解读取propery文件中,也要类型转换器来解决。

类型转换器可以分为以下两种:
1.内置类型转换器,比如:
String转Integer ,String转List,String转数组类型;
2.自定义类型转换器
比如可以自己开发一个String转Date。

类型转换器开发:
1. 使用PropertyEditorSupport,然后注册到 CustomeEditorConfigure 中;这是很早之前流行的做法,现在很少使用了;
2. 实现Converter接口,然后这个bean的名字,必须叫convertionService
createBeanInstance()就是用反射来创建对象了。

doGetBean()方法中对属性进行填充

doGetBean()中populateBean(beanName, mbd, instanceWrapper);是对属性进行填充的。

注入分为,set注入,自动注入(bean或beans标签中autowire属性),构造注入
构造注入是使用构造方法来对属性进行填充的,这应该是由createBeanInstance()方法来调用的,所以不会在中populateBean()体现。
populateBean会进行set注入和自动注入。

set注入分为:
    
    JDK类型  
    自建类型 
    
    
	@Value——JDK类型注入
    @Autowired——自建类型注入    
    @Inject
    @Resources
    
populateBean()方法中hasInstAwareBpps变量来判断是否是注解类型注入;——————AutowiredAnnotationBeanPostProcessor来处理注解的注入

非注解的属性填充是通过applyPropertyValues(beanName, mbd, bw, pvs);完成的
    
在注入时还会进行类型转换
      如果配置了自定义类型转换器的时候会调用自定义的,否则调用内置类型转换器
      
注意:不管是标签进行属性填充、还是注解进行属性填充,当这个类型是自定义类型时,都会继续走BeanFactory#getBean()方法

applyPropertyValues()方法说明:

从Spring源码看创建对象的过程_第13张图片

doGetBean()方法中初始化的操作

doGetBean()中exposedObject = initializeBean(beanName, exposedObject, mbd);是进行初始化操作的。

从Spring源码看创建对象的过程_第14张图片

问题:属性填充中的BeanPostProcessor和初始化中的BeanPostProcessor有什么区别呢?

属性填充中的BeanPostProcessor,一般情况下指的是Spring自己提供的BeanPostProcessor;

初始化中的BeanPostProcessor,一般情况下指的是程序员提供的BeanPostProcessor。

下面我们再来讨论下创建对象时,为其做AOP代理是如何进行的。

是在初始化中的BeanPostProcessor的after中进行的。

你可能感兴趣的:(spring,java,后端)