博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring容器启动流程(下)
阅读量:4223 次
发布时间:2019-05-26

本文共 17943 字,大约阅读时间需要 59 分钟。

一般来说,Spring框架启动流程大体上分成两个大的步骤:IoC容器初始化和Bean的依赖注入。

Bean的依赖注入

Bean的依赖注入大致可分为如下过程:

  • 转换对应beanName;

  • 尝试从缓存中加载单例;

  • 获取单例

  • 创建Bean

转换对应beanName

考虑到传入的beanName可能是别名,也有可能是FactoryBean,因此需要进行必要的转换。简单来说,如果是FactoryBean的话,去除前面的修饰符“&”;如果是alias,取指定alias所表示的最终beanName。

尝试从缓存中加载单例

Spring框架中尝试加载单例的代码如下:

public Object getSingleton(String beanName) {        return this.getSingleton(beanName, true);    }protected Object getSingleton(String beanName, boolean allowEarlyReference) {        Object singletonObject = this.singletonObjects.get(beanName);        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {            Map var4 = this.singletonObjects;            synchronized(this.singletonObjects) {                singletonObject = this.earlySingletonObjects.get(beanName);                if (singletonObject == null && allowEarlyReference) {                    ObjectFactory
singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } }
  • 代码中涉及到三个map类型的对象:singletonObjects、earlySingletonObjects、singletonFactories;
  • 从代码逻辑中可以看到,首先尝试从singletonObjects中加载;
  • 如果获取不到,再从earlySingletonObjects中获取;
  • 如果再获取不到,则尝试从singletonFactories里面获取beanName对应得ObjectFactory;
  • 然后调用这个ObjectFactory的getObject方法来创建bean,并放到earlySingletonObjects里面去;
  • 然后从singletonFactories删除对应的ObjectFactory。

在得到bean的实例后需要调用getObjectForBeanInstance方法来检测一下正确性,其实就是检测当前bean是否为FactoryBean类型的bean,如果是,需要调用对应的getObject方法作为返回值。

protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {        if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {            throw new BeanIsNotAFactoryException(this.transformedBeanName(name), beanInstance.getClass());        } else if (beanInstance instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {            Object object = null;            if (mbd == null) {                object = this.getCachedObjectForFactoryBean(beanName);            }            if (object == null) {                FactoryBean
factory = (FactoryBean)beanInstance; if (mbd == null && this.containsBeanDefinition(beanName)) { mbd = this.getMergedLocalBeanDefinition(beanName); } boolean synthetic = mbd != null && mbd.isSynthetic(); object = this.getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; } else { return beanInstance; } }

上述代码中对于非FactoryBean不做任何处理,而将从Factory中解析bean的工作委托给了getObjectFromFactoryBean方法。

protected Object getObjectFromFactoryBean(FactoryBean
factory, String beanName, boolean shouldPostProcess) { if (factory.isSingleton() && this.containsSingleton(beanName)) { synchronized(this.getSingletonMutex()) { Object object = this.factoryBeanObjectCache.get(beanName); if (object == null) { object = this.doGetObjectFromFactoryBean(factory, beanName); Object alreadyThere = this.factoryBeanObjectCache.get(beanName); if (alreadyThere != null) { object = alreadyThere; } else { if (object != null && shouldPostProcess) { try { object = this.postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable var9) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's singleton object failed", var9); } } this.factoryBeanObjectCache.put(beanName, object != null ? object : NULL_OBJECT); } } return object != NULL_OBJECT ? object : null; } } else { Object object = this.doGetObjectFromFactoryBean(factory, beanName); if (object != null && shouldPostProcess) { try { object = this.postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable var11) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", var11); } } return object; } }

代码中只有一处需要注意的,那就是如果bean是单例的,那就要保证全局唯一,也因为是单例,可以不必重复创建,使用缓存来提高性能。最后去调用doGetObjectFromFactoryBean方法。

private Object doGetObjectFromFactoryBean(final FactoryBean
factory, String beanName) throws BeanCreationException { Object object; try { if (System.getSecurityManager() != null) { AccessControlContext acc = this.getAccessControlContext(); try { object = AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws Exception { return factory.getObject(); } }, acc); } catch (PrivilegedActionException var6) { throw var6.getException(); } } else { object = factory.getObject(); } } catch (FactoryBeanNotInitializedException var7) { throw new BeanCurrentlyInCreationException(beanName, var7.toString()); } catch (Throwable var8) { throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", var8); } if (object == null && this.isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName, "FactoryBean which is currently in creation returned null from getObject"); } else { return object; } }

可以看到,通过直接调用getObject方法获取bean,并通过postProcessObjectFromFactoryBean方法完成相应的后处理。Spring获取bean的规则中有一条:尽可能保证所有bean初始化后都会调用注册的BeanPostProcessor的postProcessAfterInitialization方法进行处理。

获取单例

如果当前缓存中不存在对应的单例Bean,那就必须从头开始加载Bean,ObjectFactory的核心部分就是调用createBean方法。

sharedInstance = this.getSingleton(beanName, new ObjectFactory() {                    public Object getObject() throws BeansException {                        try {                            return AbstractBeanFactory.this.createBean(beanName, mbd, args);                        } catch (BeansException var2) {                            AbstractBeanFactory.this.destroySingleton(beanName);                            throw var2;                        }                    }                });
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {        if (this.logger.isDebugEnabled()) {            this.logger.debug("Creating instance of bean '" + beanName + "'");        }        this.resolveBeanClass(mbd, beanName, new Class[0]);        try {            mbd.prepareMethodOverrides();        } catch (BeanDefinitionValidationException var5) {            throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName, "Validation of method overrides failed", var5);        }        Object beanInstance;        try {            beanInstance = this.resolveBeforeInstantiation(beanName, mbd);            if (beanInstance != null) {                return beanInstance;            }        } catch (Throwable var6) {            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", var6);        }        beanInstance = this.doCreateBean(beanName, mbd, args);        if (this.logger.isDebugEnabled()) {            this.logger.debug("Finished creating instance of bean '" + beanName + "'");        }        return beanInstance;    }

在调用doCreateBean方法之前,先调用了prepareMethodOverrides和resolveBeforeInstantiation两个方法,前者完成override属性处理,后者完成bean实例化的前置处理,此处暂不叙述,读者可关注后续文章。

创建Bean

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, Object[] args) {        BeanWrapper instanceWrapper = null;        if (mbd.isSingleton()) {            //如果是单例则需要首先清除缓存            instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);        }        if (instanceWrapper == null) {            //根据指定bean使用对应的策略创建新的实例            instanceWrapper = this.createBeanInstance(beanName, mbd, args);        }        final Object bean = instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null;        Class
beanType = instanceWrapper != null ? instanceWrapper.getWrappedClass() : null; Object var7 = mbd.postProcessingLock; synchronized(mbd.postProcessingLock) { if (!mbd.postProcessed) { this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); mbd.postProcessed = true; } } //如果是单例并且允许循环依赖并且当前bean正在创建中检测到循环依赖,则需要提早曝光 boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName); if (earlySingletonExposure) { if (this.logger.isDebugEnabled()) { this.logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } this.addSingletonFactory(beanName, new ObjectFactory() { public Object getObject() throws BeansException { return AbstractAutowireCapableBeanFactory.this.getEarlyBeanReference(beanName, mbd, bean); } }); } Object exposedObject = bean; try { //填充bean,注入属性值,如果存在依赖其他bean的属性,递归初始化所依赖的bean this.populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) { exposedObject = this.initializeBean(beanName, exposedObject, mbd); } } catch (Throwable var17) { if (var17 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var17).getBeanName())) { throw (BeanCreationException)var17; } throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var17); } if (earlySingletonExposure) { Object earlySingletonReference = this.getSingleton(beanName, false); if (earlySingletonReference != null) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) { String[] dependentBeans = this.getDependentBeans(beanName); Set
actualDependentBeans = new LinkedHashSet(dependentBeans.length); String[] arr$ = dependentBeans; int len$ = dependentBeans.length; for(int i$ = 0; i$ < len$; ++i$) { String dependentBean = arr$[i$]; if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } if (!actualDependentBeans.isEmpty()) { throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been " + "wrapped. This means that said other beans do not use the final version of the " + "bean. This is often the result of over-eager type matching - consider using " + "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); } } } } try { //根据scope注册bean this.registerDisposableBeanIfNecessary(beanName, bean, mbd); return exposedObject; } catch (BeanDefinitionValidationException var16) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16); } }
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {        Class
beanClass = this.resolveBeanClass(mbd, beanName, new Class[0]); if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Bean class isn't public, and non-public access not allowed: " + beanClass.getName()); } else if (mbd.getFactoryMethodName() != null) { //如果工厂方法不为空则使用工厂方法初始化策略 return this.instantiateUsingFactoryMethod(beanName, mbd, args); } else { boolean resolved = false; boolean autowireNecessary = false; if (args == null) { Object var7 = mbd.constructorArgumentLock; synchronized(mbd.constructorArgumentLock) { //根据参数确定调用的构造方法或者工厂方法 if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; } } } if (resolved) { //确定使用构造方法自动注入还是使用默认构造方法构造 return autowireNecessary ? this.autowireConstructor(beanName, mbd, (Constructor[])null, (Object[])null) : this.instantiateBean(beanName, mbd); } else { Constructor
[] ctors = this.determineConstructorsFromBeanPostProcessors(beanClass, beanName); //确定使用构造方法自动注入还是使用默认构造方法构造 return ctors == null && mbd.getResolvedAutowireMode() != 3 && !mbd.hasConstructorArgumentValues() && ObjectUtils.isEmpty(args) ? this.instantiateBean(beanName, mbd) : this.autowireConstructor(beanName, mbd, ctors, args); } } }

从代码中可以看出,Spring通过autowireConstructor和instantiateBean两个方法创建Bean实例。前者逻辑复杂,代码量巨大,但从其功能实现的角度考虑了如下几个方面:

  • 构造函数参数的确定(隐式参数、缓存、配置文件);

  • 构造函数的确定;

  • 根据确定的构造函数转换对应的参数类型;

  • 构造函数不确定性的验证;

  • 根据实例化策略以及得到的构造函数寄构造函数参数实例化Bean。

后者逻辑简单,由于不需要考虑参数,因此直接调用实例化策略进行实例化就可以了。实例化操作结束后,需要注入属性。重点是

autowireByName和autowireByType两个方法。

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {        PropertyValues pvs = mbd.getPropertyValues();        if (bw == null) {            if (!((PropertyValues)pvs).isEmpty()) {                throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");            }        } else {            boolean continueWithPropertyPopulation = true;            if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {                Iterator i$ = this.getBeanPostProcessors().iterator();                while(i$.hasNext()) {                    BeanPostProcessor bp = (BeanPostProcessor)i$.next();                    if (bp instanceof InstantiationAwareBeanPostProcessor) {                        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;                        if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {                            continueWithPropertyPopulation = false;                            break;                        }                    }                }            }            if (continueWithPropertyPopulation) {                if (mbd.getResolvedAutowireMode() == 1 || mbd.getResolvedAutowireMode() == 2) {                    MutablePropertyValues newPvs = new MutablePropertyValues((PropertyValues)pvs);                    if (mbd.getResolvedAutowireMode() == 1) {                        this.autowireByName(beanName, mbd, bw, newPvs);                    }                    if (mbd.getResolvedAutowireMode() == 2) {                        this.autowireByType(beanName, mbd, bw, newPvs);                    }                    pvs = newPvs;                }                boolean hasInstAwareBpps = this.hasInstantiationAwareBeanPostProcessors();                boolean needsDepCheck = mbd.getDependencyCheck() != 0;                if (hasInstAwareBpps || needsDepCheck) {                    PropertyDescriptor[] filteredPds = this.filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);                    if (hasInstAwareBpps) {                        Iterator i$ = this.getBeanPostProcessors().iterator();                        while(i$.hasNext()) {                            BeanPostProcessor bp = (BeanPostProcessor)i$.next();                            if (bp instanceof InstantiationAwareBeanPostProcessor) {                                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;                                pvs = ibp.postProcessPropertyValues((PropertyValues)pvs, filteredPds, bw.getWrappedInstance(), beanName);                                if (pvs == null) {                                    return;                                }                            }                        }                    }                    if (needsDepCheck) {                        this.checkDependencies(beanName, mbd, filteredPds, (PropertyValues)pvs);                    }                }                this.applyPropertyValues(beanName, mbd, bw, (PropertyValues)pvs);            }        }    }

此时Spring已经完成了bean的实例化和属性的填充,接着便会调用用户设定的初始化方法。一般而言,用户可以有三种途径自定义初始化方法,后续文章会有详细叙述,敬请关注。

总结

笔者花了两篇博文的篇幅大致介绍了Spring容器的启动过程,还有很多细节方面并未涉及,例如循环依赖、具体属性值注入等。平时开发时对于容器启动时打印的日志信息毫无感觉,现在读者可以结合博文再去关注日志信息,相信会有更深的体会。祝好!

转载地址:http://zsgmi.baihongyu.com/

你可能感兴趣的文章
Comma2k19数据集使用
查看>>
面向自动驾驶车辆验证的抽象仿真场景生成
查看>>
一种应用于GPS反欺骗的基于MLE的RAIM改进方法
查看>>
自动驾驶汽车GPS系统数字孪生建模(一)
查看>>
自动驾驶汽车GPS系统数字孪生建模(二)
查看>>
CUDA 学习(五)、线程块
查看>>
CUDA 学习(八)、线程块调度
查看>>
CUDA 学习(九)、CUDA 内存
查看>>
CUDA 学习(十一)、共享内存
查看>>
游戏感:虚拟感觉的游戏设计师指南——第十四章 生化尖兵
查看>>
游戏感:虚拟感觉的游戏设计师指南——第十五章 超级马里奥64
查看>>
游戏感:虚拟感觉的游戏设计师指南——第十七章 游戏感的原理
查看>>
游戏感:虚拟感觉的游戏设计师指南——第十八章 我想做的游戏
查看>>
游戏设计的艺术:一本透镜的书——第十章 某些元素是游戏机制
查看>>
游戏设计的艺术:一本透镜的书——第十一章 游戏机制必须平衡
查看>>
游戏设计的艺术:一本透镜的书——第十二章 游戏机制支撑谜题
查看>>
游戏设计的艺术:一本透镜的书——第十三章 玩家通过界面玩游戏
查看>>
编写苹果游戏中心应用程序(翻译 1.3 为iOS应用程序设置游戏中心)
查看>>
编写苹果游戏中心应用程序(翻译 1.4 添加游戏工具包框架)
查看>>
编写苹果游戏中心应用程序(翻译 1.5 在游戏中心验证本地玩家)
查看>>