bean的转换过程下面这张图演示了一个可用的bean是如何从xml配置文件中演变过来的。ApplicationContext的架构图loadBean的全流程getBean的全流程
上篇博客只是对ApplicationContext相关的接口做了一个简单的介绍,作为一个高富帅级别的Spring容器,它涉及的方法实在是太多了,全部介绍是不可能的,而且大部分功能都已经在前面系列博客中做了详细的介绍,所以这篇博问介绍ApplicationContext最重要的方法(小编认为的):refresh()。refresh()是定义在ConfigurableApplicationContext类中的,如下:/***Loadorrefreshthepersistentrepresentationoftheconfiguration,*whichmightanXMLfile,properti
在前面30多篇博客中都是基于BeanFactory这个容器来进行分析的,BeanFactory容器有点儿简单,它并不适用于我们生产环境,在生产环境我们通常会选择ApplicationContext,相对于大多数人而言,它才是正规军,相比于BeanFactory这个杂牌军而言,它由如下几个区别:继承MessageSource,提供国际化的标准访问策略。继承ApplicationEventPublisher,提供强大的事件机制。扩展ResourceLoader,可以用来加载多个Resource,可以灵活访问不同的资源。对Web应用的支持。ApplicationContext下图是Applicati
在分析SpringBean实例化过程中提到Spring并不是一启动容器就开启bean的实例化进程,只有当客户端通过显示或者隐式的方式调用BeanFactory的getBean()方法来请求某个实例对象的时候,它才会触发相应bean的实例化进程,当然也可以选择直接使用ApplicationContext容器,因为该容器启动的时候会立刻调用注册到该容器所有bean定义的实例化方法。当然对于BeanFactory容器而言并不是所有的getBean()方法都会触发实例化进程,比如signleton类型的bean,该类型的bean只会在第一次调用getBean()的时候才会触发,而后续的调用则会直接返回
spring.profiles.active和@Profile这两个我相信各位都熟悉吧,主要功能是可以实现不同环境下(开发、测试、生产)参数配置的切换。其实关于环境的切换,小编在博客【死磕Spring】-----IOC之PropertyPlaceholderConfigurer的应用已经介绍了利用PropertyPlaceholderConfigurer来实现动态切换配置环境,当然这种方法需要我们自己实现,有点儿麻烦。但是对于这种非常实际的需求,Spring怎么可能没有提供呢?下面小编就问题来对Spring的环境&属性来做一个分析说明。概括Spring环境&属性由四个部分组成:
将定义bean的资源文件解析成BeanDefinition后需要将其注入容器中,这个过程由BeanDefinitionRegistry来完成。BeanDefinitionRegistry:向注册表中注册BeanDefinition实例,完成注册的过程。下图是BeanDefinitionRegistry类结构图:BeanDefinitionRegistry继承了AliasRegistry接口,其核心子类有三个:SimpleBeanDefinitionRegistry、DefaultListableBeanFactory、GenericApplicationContext。AliasRegistr
在开始分析InstantiationStrategy之前,我们先来简单回顾下bean的实例化过程:bean的创建,主要是AbstractAutowireCapableBeanFactory.doCreateBean(),在这个方法中有bean的实例化、属性注入和初始化过程,对于bean的实例化过程这是根据bean的类型来判断的,如果是单例模式,则直接从factoryBeanInstanceCache缓存中获取,否则调用createBeanInstance()创建。在createBeanInstance()中,如果Supplier不为空,则调用obtainFromSupplier()实例化bea
在实例化bean阶段,我们从BeanDefinition得到的并不是我们最终想要的Bean实例,而是BeanWrapper实例,如下:所以这里BeanWrapper是一个从BeanDefinition到Bean直接的中间产物,我们可以称它为”低级bean“,在一般情况下,我们不会在实际项目中用到它。BeanWrapper是Spring框架中重要的组件类,它就相当于一个代理类,Spring委托BeanWrapper完成Bean属性的填充工作。在bean实例被InstantiatioonStrategy创建出来后,Spring容器会将Bean实例通过BeanWrapper包裹起来,是通过BeanW
在上篇文章中小编分析了SpringConversionService类型转换体系,相信各位都对其有了一个清晰的认识,这篇博客将利用ConversionService体系来实现自己的类型转换器。ConversionService是Spring类型转换器体系中的核心接口,它定义了是否可以完成转换(canConvert())与类型转换(convert())两类接口。ConversionService有三个子类,每个子类针对不同的类型转换:Converter<S,T>:将S类型对象转为T类型对象。GenericConverter:会根据源类对象及目标类对象所在的宿主类中的上下文信息进行类型
我们知道不管bean对象里面的属性时什么类型,他们都是通过XML、Properties或者其他方式来配置这些属性对象类型的。在Spring容器加载过程中,这些属性都是以String类型加载进容器的,但是最终都需要将这些String类型的属性转换Bean对象属性所对应真正的类型,要想完成这种由字符串到具体对象的转换,就需要这种转换规则相关的信息,而这些信息以及转换过程由Spring类型转换体系来完成。我们依然以xml为例,在Spring容器加载阶段,容器将xml文件中定义的<bean>解析为BeanDefinition,BeanDefinition中存储着我们定义一个bean需要的所
在文章【死磕Spring】-----IOC之深入分析BeanFactoryPostProcessorz中提到,BeanFactoryPostProcessor作用与bean完成加载之后与bean实例化之前,是Spring提供的一种强大的扩展机制,他有两个重要的子类,一个是PropertyPlaceholderConfigurer,另一个是PropertyOverrideConfigurer,其中PropertyPlaceholderConfigurer允许我们通过配置Properties的方式来取代bean中定义的占位符,而PropertyOverrideConfigurer呢?正是我们这篇博
在博客【死磕Spring】-----IOC之深入分析PropertyPlaceholderConfigurer中了解了PropertyPlaceholderConfigurer内部实现原理,她允许我们在XML配置文件中使用占位符并将这些占位符所代表的资源单独配置到简单的properties文件中来加载。这个特性非常重要,因为它我们对Bean实例属性的配置变得非常容易控制了,主要使用场景有:动态加载配置文件,多环境切换属性加解密下面我们就第一个应用场景来做说明。利用PropertyPlaceholderConfigurer实现多环境切换在我们项目开发过程中,都会存在多个环境,如dev、test、
在上文【死磕Spring】-----IOC之深入分析BeanFactoryPostProcessor介绍了BeanFactoryPostProcessor,知道BeanFactoryPostProcessor作用域容器启动阶段,可以对解析好的BeanDefinition进行定制化处理,而其中PropertyPlaceholderConfigurer是其一个非常重要的应用,也是其子类,介绍如下:PropertyPlaceholderConfigurer允许我们用Properties文件中的属性来定义应用上下文(配置文件或者注解)什么意思,就是说我们在XML配置文件(或者其他方式,如注解方式)中使
在博客【死磕Spring】-----IOC之深入分析BeanPostProcessor深入介绍了BeanPostProcessor的实现机制。在这篇文章中提到BeanPostProcessor是Spring提供一种扩展机制,该机制允许我们在Bean实例化之后初始化之际对Bean进行增强处理(前、后置处理)。同样在Spring容器启动阶段,Spring也提供了一种容器扩展机制:BeanFactoryPostProcessor,该机制作用于容器启动阶段,允许我们在容器实例化Bean之前对注册到该容器的BeanDefinition做出修改。BeanFactoryPostProcessorBeanFa
Spring作为优秀的开源框架,它为我们提供了丰富的可扩展点,除了前面提到的Aware接口,还包括其他部分,其中一个很重要的就是BeanPostProcessor。这篇文章主要介绍BeanPostProcessor的使用以及其实现原理。我们先看BeanPostProcessor的定位:BeanPostProcessor的作用:在Bean完成实例化后,如果我们需要对其进行一些配置、增加一些自己的处理逻辑,那么请使用BeanPostProcessor。BeanPostProcessor实例首先定义一个类,该类实现BeanPostProcessor接口,如下:publicclassBeanPostP
Spring在bean初始化时进行三个检测扩展,也就是说我们可以对bean进行三个不同的定制化处理,前面两篇博客【死磕Spring】-----IOC之深入分析Aware接口和【死磕Spring】-----IOC之深入分析BeanPostProcessor已经分析了Aware接口族和BeanPostProcessor接口,这篇分析InitializingBean接口和init-method方法。InitializingBeanSpring的InitializingBean接口为bean提供了定义初始化方法的方式,它仅包含了一个方法:afterPropertiesSet()。publicinter
doCreateBean()方法主要干三件事情:实例化bean对象:createBeanInstance()属性注入:populateBean()初始化bean对象:initializeBean()而初始化bean对象时也是干了三件事情:激活Aware方法后置处理器的应用激活自定义的init方法接下来三篇文章将会详细分析这三件事情,这篇主要分析Aware接口。Aware接口定义如下:/***Markersuperinterfaceindicatingthatabeaniseligibletobe*notifiedbytheSpringcontainerofaparticularframewor
在【死磕Spring】Springbean解析篇深入分析了一个配置文件经历了哪些过程转变成了BeanDefinition,但是这个BeanDefinition并不是我们真正想要的想要的bean,因为它还仅仅只是承载了我们需要的目标bean的信息,从BeanDefinition到我们需要的目标还需要一个漫长的bean的初始化阶段,在【死磕Spring】Springbean加载阶段已经详细分析了初始化bean的过程,所以这里做一个概括性的总结。bean的初始化节点由第一次调用getBean()(显式或者隐式)开启,所以我们从这个方法开始。publicObjectgetBean(Stringname
一个bean经历了createBeanInstance()被创建出来,然后又经过一番属性注入,依赖处理,历经千辛万苦,千锤百炼,终于有点儿bean实例的样子,能堪大任了,只需要经历最后一步就破茧成蝶了。这最后一步就是初始化,也就是initializeBean(),所以这篇文章我们分析doCreateBean()中最后一步:初始化bean。protectedObjectinitializeBean(finalStringbeanName,finalObjectbean,@NullableRootBeanDefinitionmbd){if(System.getSecurityManager()!=
这篇分析doCreateBean()第三个过程:循环依赖处理。其实循环依赖并不仅仅只是在doCreateBean()中处理,其实在整个加载bean的过程中都有涉及,所以下篇内容并不仅仅只局限于doCreateBean(),而是从整个Bean的加载过程进行分析。什么是循环依赖循环依赖其实就是循环引用,就是两个或者两个以上的bean互相引用对方,最终形成一个闭环,如A依赖B,B依赖C,C依赖A,如下:循环依赖其实就是一个死循环的过程,在初始化A的时候发现引用了B,这时就会去初始化B,然后又发现B引用C,跑去初始化C,初始化C的时候发现引用了A,则又会去初始化A,依次循环永不退出,除非有终结条件。S
doCreateBean()主要用于完成bean的创建和初始化工作,我们可以将其分为四个过程:createBeanInstance()实例化beanpopulateBean()属性填充循环依赖的处理initializeBean()初始化bean第一个过程实例化bean已经在前面两篇博客分析完毕了,这篇博客开始分析属性填充,也就是populateBean(),该函数的作用是将BeanDefinition中的属性值赋值给BeanWrapper实例对象(对于BeanWrapper我们后续专门写文分析)。protectedvoidpopulateBean(StringbeanName,RootBean
createBeanInstance()用于实例化bean,它会根据不同情况选择不同的实例化策略来完成bean的初始化,主要包括:Supplier回调:obtainFromSupplier()工厂方法初始化:instantiateUsingFactoryMethod()构造函数自动注入初始化:autowireConstructor()默认构造函数注入:instantiateBean()在上篇博客(【死磕Spring】-----IOC之Factory实例化bean)中分析了Supplier回调和工厂方法初始化,这篇分析两个构造函数注入。autowireConstructor()这个初始化方法我们
这篇我们关注创建bean过程中的第一个步骤:实例化bean,对应的方法为:createBeanInstance(),如下:protectedBeanWrappercreateBeanInstance(StringbeanName,RootBeanDefinitionmbd,@NullableObject[]args){//解析bean,将bean类名解析为class引用Class<?>beanClass=resolveBeanClass(mbd,beanName);if(beanClass!=null&&!Modifier.isPublic(beanClass.ge
在上篇博客【死磕Spring】-----加载bean之分析各scope的bean创建中有一个核心方法没有讲到createBean(),该方法的如下:protectedabstractObjectcreateBean(StringbeanName,RootBeanDefinitionmbd,@NullableObject[]args)throwsBeanCreationException;该方法定义在AbstractBeanFactory中。其含义是根据给定的BeanDefinition和args实例化一个bean对象,如果该BeanDefinition存在父类,则该BeanDefinition
在Spring中存在着不同的scope,默认是singleton,还有prototype、request等等其他的scope,他们的初始化步骤是怎样的呢?这个答案在这篇博客中给出。singletonSpring的scope默认为singleton,其初始化的代码如下:if(mbd.isSingleton()){sharedInstance=getSingleton(beanName,()->{try{returncreateBean(beanName,mbd,args);}catch(BeansExceptionex){destroySingleton(beanName);throwex
继上篇博客【死磕Spring】-----加载bean之缓存中获取单例bean,如果从单例缓存中没有获取到单例bean,则说明两种情况:该bean的scope不是singleton该bean的scope是singleton,但是没有初始化完成针对这两种情况Spring是如何处理的呢?统一加载并完成初始化!这部分内容的篇幅较长,拆分为两部分,第一部分主要是一些检测、parentBeanFactory以及依赖处理,第二部分则是各个scope的初始化。if(isPrototypeCurrentlyInCreation(beanName)){thrownewBeanCurrentlyInCreation
从这篇博客开始我们开始加载bean的第一个步骤,从缓存中获取bean,代码片段如下:ObjectsharedInstance=getSingleton(beanName);if(sharedInstance!=null&&args==null){if(logger.isDebugEnabled()){if(isSingletonCurrentlyInCreation(beanName)){logger.debug("Returningeagerlycachedinstanceofsingletonbean'"+beanName+"'thatisno
前面13篇博文从源码层次分析了IOC整个初始化过程,这篇就这些内容做一个总结将其连贯起来。在前文提过,IOC容器的初始化过程分为三步骤:Resource定位、BeanDefinition的载入和解析,BeanDefinition注册。Resource定位。我们一般用外部资源来描述Bean对象,所以在初始化IOC容器的第一步就是需要定位这个外部资源。BeanDefinition的载入和解析。装载就是BeanDefinition的载入。BeanDefinitionReader读取、解析Resource资源,也就是将用户定义的Bean表示成IOC容器的内部数据结构:BeanDefinition。在I
(此图来自《Spring揭秘》)SpringIOC容器所起的作用如上图所示,它会以某种方式加载ConfigurationMetadata,将其解析注册到容器内部,然后回根据这些信息绑定整个系统的对象,最终组装成一个可用的基于轻量级容器的应用系统。Spring在实现上述功能中,将整个流程分为两个阶段:容器初始化阶段和加载bean阶段。容器初始化阶段:首先通过某种方式加载ConfigurationMetadata(主要是依据Resource、ResourceLoader两个体系),然后容器会对加载的ConfigurationMetaData进行解析和分析,并将分析的信息组装成BeanDefinit
DefaultBeanDefinitionDocumentReader.processBeanDefinition()完成Bean标签解析的核心工作,如下:protectedvoidprocessBeanDefinition(Elementele,BeanDefinitionParserDelegatedelegate){BeanDefinitionHolderbdHolder=delegate.parseBeanDefinitionElement(ele);if(bdHolder!=null){bdHolder=delegate.decorateBeanDefinitionIfRequire