- 浏览: 113394 次
- 性别:
- 来自: 北京
最新评论
Spring技术内幕——深入解析Spring架构与设计原理(一)IOC实现原理
内容较多,新开一贴,以便阅读和讨论,请管理员见谅。
IOC的基础
下面我们从IOC/AOP开始,它们是Spring平台实现的核心部分;虽然,我们一开始大多只是在这个层面上,做一些配置和外部特性的使用工作,但对这两个核心模块工作原理和运作机制的理解,对深入理解Spring平台,却是至关重要的;因为,它们同时也是Spring其他模块实现的基础。从Spring要做到的目标,也就是从简化Java EE开发的出发点来看,简单的来说,它是通过对POJO开发的支持,来具体实现的;具体的说,Spring通过为应用开发提供基于POJO的开发模式,把应用开发和复杂的Java EE服务,实现解耦,并通过提高单元测试的覆盖率,从而有效的提高整个应用的开发质量。这样一来,实际上,就需要把为POJO提供支持的,各种Java EE服务支持抽象到应用平台中去,去封装起来;而这种封装功能的实现,在Spring中,就是由IOC容器以及AOP来具体提供的,这两个模块,在很大程度上,体现了Spring作为应用开发平台的核心价值。它们的实现,是Rod.Johnson在他的另一本著作《Expert One-on-One J2EE Development without EJB》 中,所提到Without EJB设计思想的体现;同时也深刻的体现了Spring背后的设计理念。
从更深一点的技术层面上来看,因为Spring是一个基于Java语言的应用平台,如果我们能够对Java计算模型,比如像JVM虚拟机实现技术的基本原理有一些了解,会让我们对Spring实现的理解,更加的深入,这些JVM虚拟机的特性使用,包括像反射机制,代理类,字节码技术等等。它们都是在Spring实现中,涉及到的一些Java计算环境的底层技术;尽管对应用开发人员来说,可能不会直接去涉及这些JVM虚拟机底层实现的工作,但是了解这些背景知识,或多或少,对我们了解整个Spring平台的应用背景有很大的帮助;打个比方来说,就像我们在大学中,学习的那些关于计算机组织和系统方面的基本知识,比如像数字电路,计算机组成原理,汇编语言,操作系统等等这些基本课程的学习。虽然,坦率的来说,对我们这些大多数课程的学习者,在以后的工作中,可能并没有太多的机会,直接从事这么如此底层的技术开发工作;但具备这些知识背景,为我们深入理解基于这些基础技术构架起来的应用系统,毫无疑问,是不可缺少的。随着JVM虚拟机技术的发展,可以设想到的是,更多虚拟机级别的基本特性,将会持续的被应用平台开发者所关注和采用,这也是我们在学习平台实现的过程中,非常值得注意的一点,因为这些底层技术实现,毫无疑问,会对Spring应用平台的开发路线,产品策略产生重大的影响。同时,在使用Spring作为应用平台的时候,如果需要更深层次的开发和性能调优,这些底层的知识,也是我们知识库中不可缺少的部分。有了这些底层知识,理解整个系统,想来就应该障碍不大了。
IOC的一点认识
对Spring IOC的理解离不开对依赖反转模式的理解,我们知道,关于如何反转对依赖的控制,把控制权从具体业务对象手中转交到平台或者框架中,是解决面向对象系统设计复杂性和提高面向对象系统可测试性的一个有效的解决方案。这个问题触发了IoC设计模式的发展,是IoC容器要解决的核心问题。同时,也是产品化的IoC容器出现的推动力。而我觉得Spring的IoC容器,就是一个开源的实现依赖反转模式的产品。
那具体什么是IoC容器呢?它在Spring框架中到底长什么样?说了这么多,其实对IoC容器的使用者来说,我们常常接触到的BeanFactory和ApplicationContext都可以看成是容器的具体表现形式。这些就是IoC容器,或者说在Spring中提IoC容器,从实现来说,指的是一个容器系列。这也就是说,我们通常所说的IoC容器,如果深入到Spring的实现去看,会发现IoC容器实际上代表着一系列功能各异的容器产品。只是容器的功能有大有小,有各自的特点。打个比方来说,就像是百货商店里出售的商品,我们举水桶为例子,在商店中出售的水桶有大有小;制作材料也各不相同,有金属的,有塑料的等等,总之是各式各样,但只要能装水,具备水桶的基本特性,那就可以作为水桶来出售来让用户使用。这在Spring中也是一样,它有各式各样的IoC容器的实现供用户选择和使用;使用什么样的容器完全取决于用户的需要,但在使用之前如果能够了解容器的基本情况,那会对容器的使用是非常有帮助的;就像我们在购买商品时进行的对商品的考察和挑选那样。
我们从最基本的XmlBeanFactory看起,它是容器系列的最底层实现,这个容器的实现与我们在Spring应用中用到的那些上下文相比,有一个非常明显的特点,它只提供了最基本的IoC容器的功能。从它的名字中可以看出,这个IoC容器可以读取以XML形式定义的BeanDefinition。理解这一点有助于我们理解ApplicationContext与基本的BeanFactory之间的区别和联系。我们可以认为直接的BeanFactory实现是IoC容器的基本形式,而各种ApplicationContext的实现是IoC容器的高级表现形式。
仔细阅读XmlBeanFactory的源码,在一开始的注释里面已经对 XmlBeanFactory的功能做了简要的说明,从代码的注释还可以看到,这是Rod Johnson在2001年就写下的代码,可见这个类应该是Spring的元老类了。它是继承DefaultListableBeanFactory这个类的,这个DefaultListableBeanFactory就是一个很值得注意的容器!
XmlBeanFactory的功能是建立在DefaultListableBeanFactory这个基本容器的基础上的,在这个基本容器的基础上实现了其他诸如XML读取的附加功能。对于这些功能的实现原理,看一看XmlBeanFactory的代码实现就能很容易地理解。在如下的代码中可以看到,在XmlBeanFactory构造方法中需要得到Resource对象。对XmlBeanDefinitionReader对象的初始化,以及使用这个这个对象来完成loadBeanDefinitions的调用,就是这个调用启动了从Resource中载入BeanDefinitions的过程,这个loadBeanDefinitions同时也是IoC容器初始化的重要组成部分。
简单来说,IoC容器的初始化包括BeanDefinition的Resouce定位、载入和注册这三个基本的过程。我觉得重点是在载入和对BeanDefinition做解析的这个过程。可以从DefaultListableBeanFactory来入手看看IoC容器是怎样完成BeanDefinition载入的。在refresh调用完成以后,可以看到loadDefinition的调用:
这里使用 XmlBeanDefinitionReader来载入BeanDefinition到容器中,如以下代码清单所示:
关于具体的Spring BeanDefinition的解析,是在BeanDefinitionParserDelegate中完成的。这个类里包含了各种Spring Bean定义规则的处理,感兴趣的同学可以仔细研究。我们举一个例子来分析这个处理过程,比如我们最熟悉的对Bean元素的处理是怎样完成的,也就是我们在XML定义文件中出现的<bean></bean>这个最常见的元素信息是怎样被处理的。在这里,我们会看到那些熟悉的BeanDefinition定义的处理,比如id、name、aliase等属性元素。把这些元素的值从XML文件相应的元素的属性中读取出来以后,会被设置到生成的BeanDefinitionHolder中去。这些属性的解析还是比较简单的。对于其他元素配置的解析,比如各种Bean的属性配置,通过一个较为复杂的解析过程,这个过程是由parseBeanDefinitionElement来完成的。解析完成以后,会把解析结果放到BeanDefinition对象中并设置到BeanDefinitionHolder中去,如以下清单所示:
在具体生成BeanDefinition以后。我们举一个对property进行解析的例子来完成对整个BeanDefinition载入过程的分析,还是在类BeanDefinitionParserDelegate的代码中,它对BeanDefinition中的定义一层一层地进行解析,比如从属性元素集合到具体的每一个属性元素,然后才是对具体的属性值的处理。根据解析结果,对这些属性值的处理会封装成PropertyValue对象并设置到BeanDefinition对象中去,如以下代码清单所示。
比如,再往下看,我们看到像List这样的属性配置是怎样被解析的,依然在BeanDefinitionParserDelegate中:返回的是一个List对象,这个List是Spring定义的ManagedList,作为封装List这类配置定义的数据封装,如以下代码清单所示。
经过这样一层一层的解析,我们在XML文件中定义的BeanDefinition就被整个给载入到了IoC容器中,并在容器中建立了数据映射。在IoC容器中建立了对应的数据结构,或者说可以看成是POJO对象在IoC容器中的映像,这些数据结构可以以AbstractBeanDefinition为入口,让IoC容器执行索引、查询和操作。
在我的感觉中,对核心数据结构的定义和处理应该可以看成是一个软件的核心部分了。所以,这里的BeanDefinition的载入可以说是IoC容器的核心,如果说IoC容器是Spring的核心,那么这些BeanDefinition就是Spring的核心的核心了!
呵呵,这部分代码数量不小,但如果掌握这条主线,其他都可以举一反三吧,就像我们掌握了操作系统启动的过程,以及在操作系统设计中的核心数据结构像进程数据结构,文件系统数据结构,网络协议数据结构的设计和处理一样,对整个系统的设计原理,包括移植,驱动开发和应用开发,是非常有帮助的!
IOC的基础
下面我们从IOC/AOP开始,它们是Spring平台实现的核心部分;虽然,我们一开始大多只是在这个层面上,做一些配置和外部特性的使用工作,但对这两个核心模块工作原理和运作机制的理解,对深入理解Spring平台,却是至关重要的;因为,它们同时也是Spring其他模块实现的基础。从Spring要做到的目标,也就是从简化Java EE开发的出发点来看,简单的来说,它是通过对POJO开发的支持,来具体实现的;具体的说,Spring通过为应用开发提供基于POJO的开发模式,把应用开发和复杂的Java EE服务,实现解耦,并通过提高单元测试的覆盖率,从而有效的提高整个应用的开发质量。这样一来,实际上,就需要把为POJO提供支持的,各种Java EE服务支持抽象到应用平台中去,去封装起来;而这种封装功能的实现,在Spring中,就是由IOC容器以及AOP来具体提供的,这两个模块,在很大程度上,体现了Spring作为应用开发平台的核心价值。它们的实现,是Rod.Johnson在他的另一本著作《Expert One-on-One J2EE Development without EJB》 中,所提到Without EJB设计思想的体现;同时也深刻的体现了Spring背后的设计理念。
从更深一点的技术层面上来看,因为Spring是一个基于Java语言的应用平台,如果我们能够对Java计算模型,比如像JVM虚拟机实现技术的基本原理有一些了解,会让我们对Spring实现的理解,更加的深入,这些JVM虚拟机的特性使用,包括像反射机制,代理类,字节码技术等等。它们都是在Spring实现中,涉及到的一些Java计算环境的底层技术;尽管对应用开发人员来说,可能不会直接去涉及这些JVM虚拟机底层实现的工作,但是了解这些背景知识,或多或少,对我们了解整个Spring平台的应用背景有很大的帮助;打个比方来说,就像我们在大学中,学习的那些关于计算机组织和系统方面的基本知识,比如像数字电路,计算机组成原理,汇编语言,操作系统等等这些基本课程的学习。虽然,坦率的来说,对我们这些大多数课程的学习者,在以后的工作中,可能并没有太多的机会,直接从事这么如此底层的技术开发工作;但具备这些知识背景,为我们深入理解基于这些基础技术构架起来的应用系统,毫无疑问,是不可缺少的。随着JVM虚拟机技术的发展,可以设想到的是,更多虚拟机级别的基本特性,将会持续的被应用平台开发者所关注和采用,这也是我们在学习平台实现的过程中,非常值得注意的一点,因为这些底层技术实现,毫无疑问,会对Spring应用平台的开发路线,产品策略产生重大的影响。同时,在使用Spring作为应用平台的时候,如果需要更深层次的开发和性能调优,这些底层的知识,也是我们知识库中不可缺少的部分。有了这些底层知识,理解整个系统,想来就应该障碍不大了。
IOC的一点认识
对Spring IOC的理解离不开对依赖反转模式的理解,我们知道,关于如何反转对依赖的控制,把控制权从具体业务对象手中转交到平台或者框架中,是解决面向对象系统设计复杂性和提高面向对象系统可测试性的一个有效的解决方案。这个问题触发了IoC设计模式的发展,是IoC容器要解决的核心问题。同时,也是产品化的IoC容器出现的推动力。而我觉得Spring的IoC容器,就是一个开源的实现依赖反转模式的产品。
那具体什么是IoC容器呢?它在Spring框架中到底长什么样?说了这么多,其实对IoC容器的使用者来说,我们常常接触到的BeanFactory和ApplicationContext都可以看成是容器的具体表现形式。这些就是IoC容器,或者说在Spring中提IoC容器,从实现来说,指的是一个容器系列。这也就是说,我们通常所说的IoC容器,如果深入到Spring的实现去看,会发现IoC容器实际上代表着一系列功能各异的容器产品。只是容器的功能有大有小,有各自的特点。打个比方来说,就像是百货商店里出售的商品,我们举水桶为例子,在商店中出售的水桶有大有小;制作材料也各不相同,有金属的,有塑料的等等,总之是各式各样,但只要能装水,具备水桶的基本特性,那就可以作为水桶来出售来让用户使用。这在Spring中也是一样,它有各式各样的IoC容器的实现供用户选择和使用;使用什么样的容器完全取决于用户的需要,但在使用之前如果能够了解容器的基本情况,那会对容器的使用是非常有帮助的;就像我们在购买商品时进行的对商品的考察和挑选那样。
我们从最基本的XmlBeanFactory看起,它是容器系列的最底层实现,这个容器的实现与我们在Spring应用中用到的那些上下文相比,有一个非常明显的特点,它只提供了最基本的IoC容器的功能。从它的名字中可以看出,这个IoC容器可以读取以XML形式定义的BeanDefinition。理解这一点有助于我们理解ApplicationContext与基本的BeanFactory之间的区别和联系。我们可以认为直接的BeanFactory实现是IoC容器的基本形式,而各种ApplicationContext的实现是IoC容器的高级表现形式。
仔细阅读XmlBeanFactory的源码,在一开始的注释里面已经对 XmlBeanFactory的功能做了简要的说明,从代码的注释还可以看到,这是Rod Johnson在2001年就写下的代码,可见这个类应该是Spring的元老类了。它是继承DefaultListableBeanFactory这个类的,这个DefaultListableBeanFactory就是一个很值得注意的容器!
- publicclassXmlBeanFactoryextendsDefaultListableBeanFactory{
- privatefinalXmlBeanDefinitionReaderreader=newXmlBeanDefinitionReader(this);
- publicXmlBeanFactory(Resourceresource)throwsBeansException{
- this(resource,null);
- }
- publicXmlBeanFactory(Resourceresource,BeanFactoryparentBeanFactory)throwsBeansException{
- super(parentBeanFactory);
- this.reader.loadBeanDefinitions(resource);
- }
- }
XmlBeanFactory的功能是建立在DefaultListableBeanFactory这个基本容器的基础上的,在这个基本容器的基础上实现了其他诸如XML读取的附加功能。对于这些功能的实现原理,看一看XmlBeanFactory的代码实现就能很容易地理解。在如下的代码中可以看到,在XmlBeanFactory构造方法中需要得到Resource对象。对XmlBeanDefinitionReader对象的初始化,以及使用这个这个对象来完成loadBeanDefinitions的调用,就是这个调用启动了从Resource中载入BeanDefinitions的过程,这个loadBeanDefinitions同时也是IoC容器初始化的重要组成部分。
简单来说,IoC容器的初始化包括BeanDefinition的Resouce定位、载入和注册这三个基本的过程。我觉得重点是在载入和对BeanDefinition做解析的这个过程。可以从DefaultListableBeanFactory来入手看看IoC容器是怎样完成BeanDefinition载入的。在refresh调用完成以后,可以看到loadDefinition的调用:
- publicabstractclassAbstractXmlApplicationContextextendsAbstractRefreshableConfigApplicationContext{
- publicAbstractXmlApplicationContext(){
- }
- publicAbstractXmlApplicationContext(ApplicationContextparent){
- super(parent);
- }
- //这里是实现loadBeanDefinitions的地方
- protectedvoidloadBeanDefinitions(DefaultListableBeanFactorybeanFactory)throwsIOException{
- //CreateanewXmlBeanDefinitionReaderforthegivenBeanFactory.
- //创建XmlBeanDefinitionReader,并通过回调设置到BeanFactory中去,创建BeanFactory的使用的也是DefaultListableBeanFactory。
- XmlBeanDefinitionReaderbeanDefinitionReader=newXmlBeanDefinitionReader(beanFactory);
- //Configurethebeandefinitionreaderwiththiscontext's
- //resourceloadingenvironment.
- //这里设置XmlBeanDefinitionReader,为XmlBeanDefinitionReader配置ResourceLoader,因为DefaultResourceLoader是父类,所以this可以直接被使用
- beanDefinitionReader.setResourceLoader(this);
- beanDefinitionReader.setEntityResolver(newResourceEntityResolver(this));
- //Allowasubclasstoprovidecustominitializationofthereader,
- //thenproceedwithactuallyloadingthebeandefinitions.
- //这是启动Bean定义信息载入的过程
- initBeanDefinitionReader(beanDefinitionReader);
- loadBeanDefinitions(beanDefinitionReader);
- }
- protectedvoidinitBeanDefinitionReader(XmlBeanDefinitionReaderbeanDefinitionReader){
- }
这里使用 XmlBeanDefinitionReader来载入BeanDefinition到容器中,如以下代码清单所示:
- //这里是调用的入口。
- publicintloadBeanDefinitions(Resourceresource)throwsBeanDefinitionStoreException{
- returnloadBeanDefinitions(newEncodedResource(resource));
- }
- //这里是载入XML形式的BeanDefinition的地方。
- publicintloadBeanDefinitions(EncodedResourceencodedResource)throwsBeanDefinitionStoreException{
- Assert.notNull(encodedResource,"EncodedResourcemustnotbenull");
- if(logger.isInfoEnabled()){
- logger.info("LoadingXMLbeandefinitionsfrom"+encodedResource.getResource());
- }
- Set<EncodedResource>currentResources=this.resourcesCurrentlyBeingLoaded.get();
- if(currentResources==null){
- currentResources=newHashSet<EncodedResource>(4);
- this.resourcesCurrentlyBeingLoaded.set(currentResources);
- }
- if(!currentResources.add(encodedResource)){
- thrownewBeanDefinitionStoreException(
- "Detectedrecursiveloadingof"+encodedResource+"-checkyourimportdefinitions!");
- }
- //这里得到XML文件,并得到IO的InputSource准备进行读取。
- try{
- InputStreaminputStream=encodedResource.getResource().getInputStream();
- try{
- InputSourceinputSource=newInputSource(inputStream);
- if(encodedResource.getEncoding()!=null){
- inputSource.setEncoding(encodedResource.getEncoding());
- }
- returndoLoadBeanDefinitions(inputSource,encodedResource.getResource());
- }
- finally{
- inputStream.close();
- }
- }
- catch(IOExceptionex){
- thrownewBeanDefinitionStoreException(
- "IOExceptionparsingXMLdocumentfrom"+encodedResource.getResource(),ex);
- }
- finally{
- currentResources.remove(encodedResource);
- if(currentResources.isEmpty()){
- this.resourcesCurrentlyBeingLoaded.set(null);
- }
- }
- }
- //具体的读取过程可以在doLoadBeanDefinitions方法中找到:
- //这是从特定的XML文件中实际载入BeanDefinition的地方
- protectedintdoLoadBeanDefinitions(InputSourceinputSource,Resourceresource)
- throwsBeanDefinitionStoreException{
- try{
- intvalidationMode=getValidationModeForResource(resource);
- //这里取得XML文件的Document对象,这个解析过程是由documentLoader完成的,这个documentLoader是DefaultDocumentLoader,在定义documentLoader的地方创建
- Documentdoc=this.documentLoader.loadDocument(
- inputSource,getEntityResolver(),this.errorHandler,validationMode,isNamespaceAware());
- //这里启动的是对BeanDefinition解析的详细过程,这个解析会使用到Spring的Bean配置规则,是我们下面需要详细关注的地方。
- returnregisterBeanDefinitions(doc,resource);
- }
- catch(BeanDefinitionStoreExceptionex){
- throwex;
- }
- catch(SAXParseExceptionex){
- thrownewXmlBeanDefinitionStoreException(resource.getDescription(),
- "Line"+ex.getLineNumber()+"inXMLdocumentfrom"+resource+"isinvalid",ex);
- }
- catch(SAXExceptionex){
- thrownewXmlBeanDefinitionStoreException(resource.getDescription(),
- "XMLdocumentfrom"+resource+"isinvalid",ex);
- }
- catch(ParserConfigurationExceptionex){
- thrownewBeanDefinitionStoreException(resource.getDescription(),
- "ParserconfigurationexceptionparsingXMLfrom"+resource,ex);
- }
- catch(IOExceptionex){
- thrownewBeanDefinitionStoreException(resource.getDescription(),
- "IOExceptionparsingXMLdocumentfrom"+resource,ex);
- }
- catch(Throwableex){
- thrownewBeanDefinitionStoreException(resource.getDescription(),
- "UnexpectedexceptionparsingXMLdocumentfrom"+resource,ex);
- }
- }
关于具体的Spring BeanDefinition的解析,是在BeanDefinitionParserDelegate中完成的。这个类里包含了各种Spring Bean定义规则的处理,感兴趣的同学可以仔细研究。我们举一个例子来分析这个处理过程,比如我们最熟悉的对Bean元素的处理是怎样完成的,也就是我们在XML定义文件中出现的<bean></bean>这个最常见的元素信息是怎样被处理的。在这里,我们会看到那些熟悉的BeanDefinition定义的处理,比如id、name、aliase等属性元素。把这些元素的值从XML文件相应的元素的属性中读取出来以后,会被设置到生成的BeanDefinitionHolder中去。这些属性的解析还是比较简单的。对于其他元素配置的解析,比如各种Bean的属性配置,通过一个较为复杂的解析过程,这个过程是由parseBeanDefinitionElement来完成的。解析完成以后,会把解析结果放到BeanDefinition对象中并设置到BeanDefinitionHolder中去,如以下清单所示:
- publicBeanDefinitionHolderparseBeanDefinitionElement(Elementele,BeanDefinitioncontainingBean){
- //这里取得在<bean>元素中定义的id、name和aliase属性的值
- Stringid=ele.getAttribute(ID_ATTRIBUTE);
- StringnameAttr=ele.getAttribute(NAME_ATTRIBUTE);
- List<String>aliases=newArrayList<String>();
- if(StringUtils.hasLength(nameAttr)){
- String[]nameArr=StringUtils.tokenizeToStringArray(nameAttr,BEAN_NAME_DELIMITERS);
- aliases.addAll(Arrays.asList(nameArr));
- }
- StringbeanName=id;
- if(!StringUtils.hasText(beanName)&&!aliases.isEmpty()){
- beanName=aliases.remove(0);
- if(logger.isDebugEnabled()){
- logger.debug("NoXML'id'specified-using'"+beanName+
- "'asbeannameand"+aliases+"asaliases");
- }
- }
- if(containingBean==null){
- checkNameUniqueness(beanName,aliases,ele);
- }
- //这个方法会引发对bean元素的详细解析
- AbstractBeanDefinitionbeanDefinition=parseBeanDefinitionElement(ele,beanName,containingBean);
- if(beanDefinition!=null){
- if(!StringUtils.hasText(beanName)){
- try{
- if(containingBean!=null){
- beanName=BeanDefinitionReaderUtils.generateBeanName(
- beanDefinition,this.readerContext.getRegistry(),true);
- }
- else{
- beanName=this.readerContext.generateBeanName(beanDefinition);
- //Registeranaliasfortheplainbeanclassname,ifstillpossible,
- //ifthegeneratorreturnedtheclassnameplusasuffix.
- //ThisisexpectedforSpring1.2/2.0backwardscompatibility.
- StringbeanClassName=beanDefinition.getBeanClassName();
- if(beanClassName!=null&&
- beanName.startsWith(beanClassName)&&beanName.length()>beanClassName.length()&&
- !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)){
- aliases.add(beanClassName);
- }
- }
- if(logger.isDebugEnabled()){
- logger.debug("NeitherXML'id'nor'name'specified-"+
- "usinggeneratedbeanname["+beanName+"]");
- }
- }
- catch(Exceptionex){
- error(ex.getMessage(),ele);
- returnnull;
- }
- }
- String[]aliasesArray=StringUtils.toStringArray(aliases);
- returnnewBeanDefinitionHolder(beanDefinition,beanName,aliasesArray);
- }
- returnnull;
- }
在具体生成BeanDefinition以后。我们举一个对property进行解析的例子来完成对整个BeanDefinition载入过程的分析,还是在类BeanDefinitionParserDelegate的代码中,它对BeanDefinition中的定义一层一层地进行解析,比如从属性元素集合到具体的每一个属性元素,然后才是对具体的属性值的处理。根据解析结果,对这些属性值的处理会封装成PropertyValue对象并设置到BeanDefinition对象中去,如以下代码清单所示。
- /**
- *这里对指定bean元素的property子元素集合进行解析。
- */
- publicvoidparsePropertyElements(ElementbeanEle,BeanDefinitionbd){
- //遍历所有bean元素下定义的property元素
- NodeListnl=beanEle.getChildNodes();
- for(inti=0;i<nl.getLength();i++){
- Nodenode=nl.item(i);
- if(nodeinstanceofElement&&DomUtils.nodeNameEquals(node,PROPERTY_ELEMENT)){
- //在判断是property元素后对该property元素进行解析的过程
- parsePropertyElement((Element)node,bd);
- }
- }
- }
- publicvoidparsePropertyElement(Elementele,BeanDefinitionbd){
- //这里取得property的名字
- StringpropertyName=ele.getAttribute(NAME_ATTRIBUTE);
- if(!StringUtils.hasLength(propertyName)){
- error("Tag'property'musthavea'name'attribute",ele);
- return;
- }
- this.parseState.push(newPropertyEntry(propertyName));
- try{
- //如果同一个bean中已经有同名的存在,则不进行解析,直接返回。也就是说,如果在同一个bean中有同名的property设置,那么起作用的只是第一个。
- if(bd.getPropertyValues().contains(propertyName)){
- error("Multiple'property'definitionsforproperty'"+propertyName+"'",ele);
- return;
- }
- //这里是解析property值的地方,返回的对象对应对Bean定义的property属性设置的解析结果,这个解析结果会封装到PropertyValue对象中,然后设置到BeanDefinitionHolder中去。
- Objectval=parsePropertyValue(ele,bd,propertyName);
- PropertyValuepv=newPropertyValue(propertyName,val);
- parseMetaElements(ele,pv);
- pv.setSource(extractSource(ele));
- bd.getPropertyValues().addPropertyValue(pv);
- }
- finally{
- this.parseState.pop();
- }
- }
- /**
- *这里取得property元素的值,也许是一个list或其他。
- */
- publicObjectparsePropertyValue(Elementele,BeanDefinitionbd,StringpropertyName){
- StringelementName=(propertyName!=null)?
- "<property>elementforproperty'"+propertyName+"'":
- "<constructor-arg>element";
- //Shouldonlyhaveonechildelement:ref,value,list,etc.
- NodeListnl=ele.getChildNodes();
- ElementsubElement=null;
- for(inti=0;i<nl.getLength();i++){
- Nodenode=nl.item(i);
- if(nodeinstanceofElement&&!DomUtils.nodeNameEquals(node,DESCRIPTION_ELEMENT)&&
- !DomUtils.nodeNameEquals(node,META_ELEMENT)){
- //Childelementiswhatwe'relookingfor.
- if(subElement!=null){
- error(elementName+"mustnotcontainmorethanonesub-element",ele);
- }
- else{
- subElement=(Element)node;
- }
- }
- }
- //这里判断property的属性,是ref还是value,不允许同时是ref和value。
- booleanhasRefAttribute=ele.hasAttribute(REF_ATTRIBUTE);
- booleanhasValueAttribute=ele.hasAttribute(VALUE_ATTRIBUTE);
- if((hasRefAttribute&&hasValueAttribute)||
- ((hasRefAttribute||hasValueAttribute)&&subElement!=null)){
- error(elementName+
- "isonlyallowedtocontaineither'ref'attributeOR'value'attributeORsub-element",ele);
- }
- //如果是ref,创建一个ref的数据对象RuntimeBeanReference,这个对象封装了ref的信息。
- if(hasRefAttribute){
- StringrefName=ele.getAttribute(REF_ATTRIBUTE);
- if(!StringUtils.hasText(refName)){
- error(elementName+"containsempty'ref'attribute",ele);
- }
- RuntimeBeanReferenceref=newRuntimeBeanReference(refName);
- ref.setSource(extractSource(ele));
- returnref;
- }//如果是value,创建一个value的数据对象TypedStringValue,这个对象封装了value的信息。
- elseif(hasValueAttribute){
- TypedStringValuevalueHolder=newTypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
- valueHolder.setSource(extractSource(ele));
- returnvalueHolder;
- }//如果还有子元素,触发对子元素的解析
- elseif(subElement!=null){
- returnparsePropertySubElement(subElement,bd);
- }
- else{
- //Neitherchildelementnor"ref"or"value"attributefound.
- error(elementName+"mustspecifyareforvalue",ele);
- returnnull;
- }
- }
比如,再往下看,我们看到像List这样的属性配置是怎样被解析的,依然在BeanDefinitionParserDelegate中:返回的是一个List对象,这个List是Spring定义的ManagedList,作为封装List这类配置定义的数据封装,如以下代码清单所示。
- publicListparseListElement(ElementcollectionEle,BeanDefinitionbd){
- StringdefaultElementType=collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
- NodeListnl=collectionEle.getChildNodes();
- ManagedList<Object>target=newManagedList<Object>(nl.getLength());
- target.setSource(extractSource(collectionEle));
- target.setElementTypeName(defaultElementType);
- target.setMergeEnabled(parseMergeAttribute(collectionEle));
- //具体的List元素的解析过程。
- parseCollectionElements(nl,target,bd,defaultElementType);
- returntarget;
- }
- protectedvoidparseCollectionElements(
- NodeListelementNodes,Collection<Object>target,BeanDefinitionbd,StringdefaultElementType){
- //遍历所有的元素节点,并判断其类型是否为Element。
- for(inti=0;i<elementNodes.getLength();i++){
- Nodenode=elementNodes.item(i);
- if(nodeinstanceofElement&&!DomUtils.nodeNameEquals(node,DESCRIPTION_ELEMENT)){
- //加入到target中去,target是一个ManagedList,同时触发对下一层子元素的解析过程,这是一个递归的调用。
- target.add(parsePropertySubElement((Element)node,bd,defaultElementType));
- }
- }
- }
经过这样一层一层的解析,我们在XML文件中定义的BeanDefinition就被整个给载入到了IoC容器中,并在容器中建立了数据映射。在IoC容器中建立了对应的数据结构,或者说可以看成是POJO对象在IoC容器中的映像,这些数据结构可以以AbstractBeanDefinition为入口,让IoC容器执行索引、查询和操作。
在我的感觉中,对核心数据结构的定义和处理应该可以看成是一个软件的核心部分了。所以,这里的BeanDefinition的载入可以说是IoC容器的核心,如果说IoC容器是Spring的核心,那么这些BeanDefinition就是Spring的核心的核心了!
呵呵,这部分代码数量不小,但如果掌握这条主线,其他都可以举一反三吧,就像我们掌握了操作系统启动的过程,以及在操作系统设计中的核心数据结构像进程数据结构,文件系统数据结构,网络协议数据结构的设计和处理一样,对整个系统的设计原理,包括移植,驱动开发和应用开发,是非常有帮助的!
评论
22 楼chris_zley2010-07-08引用
如果有个整体类图就好了
BeanDefinitionParserDelegate这个类跟之前loadBeanDefinitions是怎么连接的?好像这里断了
按我的通俗理解,从这里开始就是xml解析了吧,也就是bean载入Ioc容器的过程?
BeanDefinitionParserDelegate这个类跟之前loadBeanDefinitions是怎么连接的?好像这里断了
按我的通俗理解,从这里开始就是xml解析了吧,也就是bean载入Ioc容器的过程?
Hi,jiwenke,您在讲解spring ioc的时候,可否先介绍下BeanFactory的整个的继承体系,就是BeanFactory下面的子类各有哪些特点,然后根据这个体系在深入到bean对象生命周期的加载和实例化,这样是否会能够让大家更清楚知道IOC容器的整个体系.比如spring 下面的AutowireCapableBeanFactory实现了自动装配的功能
anykey1009 写道
- publicabstractclassAbstractXmlApplicationContextextendsAbstractRefreshableConfigApplicationContext{
- publicAbstractXmlApplicationContext(){
- }
- publicAbstractXmlApplicationContext(ApplicationContextparent){
- super(parent);
- }
- //这里是实现loadBeanDefinitions的地方
- protectedvoidloadBeanDefinitions(DefaultListableBeanFactorybeanFactory)throwsIOException{
- //CreateanewXmlBeanDefinitionReaderforthegivenBeanFactory.
- //创建XmlBeanDefinitionReader,并通过回调设置到BeanFactory中去,创建BeanFactory的使用的也是DefaultListableBeanFactory。
- XmlBeanDefinitionReaderbeanDefinitionReader=newXmlBeanDefinitionReader(beanFactory);
- //Configurethebeandefinitionreaderwiththiscontext's
- //resourceloadingenvironment.
- //这里设置XmlBeanDefinitionReader,为XmlBeanDefinitionReader配置ResourceLoader,因为DefaultResourceLoader是父类,所以this可以直接被使用
- beanDefinitionReader.setResourceLoader(this);
- beanDefinitionReader.setEntityResolver(newResourceEntityResolver(this));
- //Allowasubclasstoprovidecustominitializationofthereader,
- //thenproceedwithactuallyloadingthebeandefinitions.
- //这是启动Bean定义信息载入的过程
- initBeanDefinitionReader(beanDefinitionReader);
- loadBeanDefinitions(beanDefinitionReader);
- }
- protectedvoidinitBeanDefinitionReader(XmlBeanDefinitionReaderbeanDefinitionReader){
- }
这个类一直没看明白,跟上下有什么联系吗?
继续研究中。。。够我学一阵的了
PS:我是spring新手,这个类我看是个abstract类啊,那么this指的什么呢?顺便帮我补下java基础^_^
这个类我也没怎么看懂放在这儿有什么意思,可能是为了举例说明“IoC容器的高级表现形式”的吧,希望楼主给出明确的解答。
baishuo491 写道
写得真好,不知道楼主能不能写一篇关于阅读开源框架源代码具体方法的文章,新手不知道如何下手
谢谢鼓励啊!我是使用ECLIPSE+SVN来从Spring的代码库里下载的,基本的过程,我都写在书里了,到时书上市了,去翻翻看看就行了,大概有一章吧,篇幅不多,基本上算是我看源代码的一点经验吧。
16 楼baishuo4912009-12-11引用
写得真好,不知道楼主能不能写一篇关于阅读开源框架源代码具体方法的文章,新手不知道如何下手
zhangyou1010 写道
代码基本可以看懂,但看完没撒感觉,没有那种全局感。可能功力还是不够吧。
惭愧惭愧,是我写得大局感不够。我个人感觉,线是串起来了,面却没有形成。的确是功力的问题,要努力啊!
14 楼zhangyou10102009-12-10引用
代码基本可以看懂,但看完没撒感觉,没有那种全局感。可能功力还是不够吧。
linux1689 写道
出视频是个好主意,不知道作者是否有时间操作?
呵呵,现在还是集中精力,先把要出的书弄好吧。只有两点希望,一是和大家分享,二是虽然网上已经有不少的资料,但对我们这些从小就习惯从书本学习的人,有一本书,看起来会舒服些。但是,买书需要读者花钱,这可和网上不一样,所以责任感觉不一样啊,“无功不受禄”,还是希望能够尽力做到物有所值吧。
anykey1009 写道
gogole_09 写道
anykey1009 写道
- publicabstractclassAbstractXmlApplicationContextextendsAbstractRefreshableConfigApplicationContext{
- publicAbstractXmlApplicationContext(){
- }
- publicAbstractXmlApplicationContext(ApplicationContextparent){
- super(parent);
- }
- //这里是实现loadBeanDefinitions的地方
- protectedvoidloadBeanDefinitions(DefaultListableBeanFactorybeanFactory)throwsIOException{
- //CreateanewXmlBeanDefinitionReaderforthegivenBeanFactory.
- //创建XmlBeanDefinitionReader,并通过回调设置到BeanFactory中去,创建BeanFactory的使用的也是DefaultListableBeanFactory。
- XmlBeanDefinitionReaderbeanDefinitionReader=newXmlBeanDefinitionReader(beanFactory);
- //Configurethebeandefinitionreaderwiththiscontext's
- //resourceloadingenvironment.
- //这里设置XmlBeanDefinitionReader,为XmlBeanDefinitionReader配置ResourceLoader,因为DefaultResourceLoader是父类,所以this可以直接被使用
- beanDefinitionReader.setResourceLoader(this);
- beanDefinitionReader.setEntityResolver(newResourceEntityResolver(this));
- //Allowasubclasstoprovidecustominitializationofthereader,
- //thenproceedwithactuallyloadingthebeandefinitions.
- //这是启动Bean定义信息载入的过程
- initBeanDefinitionReader(beanDefinitionReader);
- loadBeanDefinitions(beanDefinitionReader);
- }
- protectedvoidinitBeanDefinitionReader(XmlBeanDefinitionReaderbeanDefinitionReader){
- }
这个类一直没看明白,跟上下有什么联系吗?
继续研究中。。。够我学一阵的了
PS:我是spring新手,这个类我看是个abstract类啊,那么this指的什么呢?顺便帮我补下java基础^_^
一般来说,在抽象类中使用this 通常是获取的子类吧, 我记得struts1.x的DispatcherAction类也使用过类似的技巧来获取它指定执行的是哪个方法. 附件有我以前自己仿的一个例子,可以下去看看,写得比较简单,只是描述了下大概的实现过程。
嗯。。谢谢啊,例子我看过了,又学到了点东西[color=red],貌似反射在框架中用的挺多的吧。。。
PS:楼主有没有出视频的意向。。哈哈,我看这大篇幅的文字,头都大了[/color]
曾经听一个人说过,框架的基本实现无非就是 反射+xml ,虽然有点牵强,但是观看大部分框架,这两部分确实实实在在都存在的。
楼主出视频的话,相信又可以带我们升一个层次啦。…… 哈哈,所以同样支持在出书的基础上,加上视频版解说,比较很多东西来说,语言总比文字直观很多。 一言胜千文啊。
huangtian549 写道
对这本书很期待!
如果12月上旬出版,可能已经定稿了,但还想提个建议, 希望书中多分析一下代码为什么这么实现,不为了读代码而读代码,多告诉大家一下框架这么设计有什么好处,明白了好处以后,才能在以后设计出适合自己的框架,提高自己的代码质量,我想可能是大家对spring源代码感兴趣的原因,(也许作者就是这么写的,那就多说了)
反正我是对一本能解析Spring源码的书是很期待的,出版后我会立刻去买的。
刚刚脱稿,已经到编辑那里了,是在平时手记基础上做的挖掘。意图是希望理出一条SPRING实现的基本脉络,依托源代码的相关解读,毕竟源代码是最可信赖的。
9 楼huangtian5492009-11-05引用
jiwenke 写道
linux1689 写道
我提前爆料一下,楼主的确要出一本Spring源代码剖析的书,书名叫《Spring技术内幕——深入解析Spring架构与设计原理》,这本书一般的源代码剖析类书不同,它更专注于框架的设计原理与架构思想。
这本书大概会在12月上旬出版,敬请各位关注。
这本书大概会在12月上旬出版,敬请各位关注。
书稿正在准备中,但主要的思想和线索都有了。我会先和大家一起讨论,希望大家多提意见!
对这本书很期待!
如果12月上旬出版,可能已经定稿了,但还想提个建议, 希望书中多分析一下代码为什么这么实现,不为了读代码而读代码,多告诉大家一下框架这么设计有什么好处,明白了好处以后,才能在以后设计出适合自己的框架,提高自己的代码质量,我想可能是大家对spring源代码感兴趣的原因,(也许作者就是这么写的,那就多说了)
反正我是对一本能解析Spring源码的书是很期待的,出版后我会立刻去买的。
linux1689 写道
我提前爆料一下,楼主的确要出一本Spring源代码剖析的书,书名叫《Spring技术内幕——深入解析Spring架构与设计原理》,这本书一般的源代码剖析类书不同,它更专注于框架的设计原理与架构思想。
这本书大概会在12月上旬出版,敬请各位关注。
这本书大概会在12月上旬出版,敬请各位关注。
书稿正在准备中,但主要的思想和线索都有了。我会先和大家一起讨论,希望大家多提意见!
7 楼anykey10092009-10-28引用
gogole_09 写道
anykey1009 写道
- publicabstractclassAbstractXmlApplicationContextextendsAbstractRefreshableConfigApplicationContext{
- publicAbstractXmlApplicationContext(){
- }
- publicAbstractXmlApplicationContext(ApplicationContextparent){
- super(parent);
- }
- //这里是实现loadBeanDefinitions的地方
- protectedvoidloadBeanDefinitions(DefaultListableBeanFactorybeanFactory)throwsIOException{
- //CreateanewXmlBeanDefinitionReaderforthegivenBeanFactory.
- //创建XmlBeanDefinitionReader,并通过回调设置到BeanFactory中去,创建BeanFactory的使用的也是DefaultListableBeanFactory。
- XmlBeanDefinitionReaderbeanDefinitionReader=newXmlBeanDefinitionReader(beanFactory);
- //Configurethebeandefinitionreaderwiththiscontext's
- //resourceloadingenvironment.
- //这里设置XmlBeanDefinitionReader,为XmlBeanDefinitionReader配置ResourceLoader,因为DefaultResourceLoader是父类,所以this可以直接被使用
- beanDefinitionReader.setResourceLoader(this);
- beanDefinitionReader.setEntityResolver(newResourceEntityResolver(this));
- //Allowasubclasstoprovidecustominitializationofthereader,
- //thenproceedwithactuallyloadingthebeandefinitions.
- //这是启动Bean定义信息载入的过程
- initBeanDefinitionReader(beanDefinitionReader);
- loadBeanDefinitions(beanDefinitionReader);
- }
- protectedvoidinitBeanDefinitionReader(XmlBeanDefinitionReaderbeanDefinitionReader){
- }
这个类一直没看明白,跟上下有什么联系吗?
继续研究中。。。够我学一阵的了
PS:我是spring新手,这个类我看是个abstract类啊,那么this指的什么呢?顺便帮我补下java基础^_^
一般来说,在抽象类中使用this 通常是获取的子类吧, 我记得struts1.x的DispatcherAction类也使用过类似的技巧来获取它指定执行的是哪个方法. 附件有我以前自己仿的一个例子,可以下去看看,写得比较简单,只是描述了下大概的实现过程。
嗯。。谢谢啊,例子我看过了,又学到了点东西,貌似反射在框架中用的挺多的吧。。。
PS:楼主有没有出视频的意向。。哈哈,我看这大篇幅的文字,头都大了
anykey1009 写道
- publicabstractclassAbstractXmlApplicationContextextendsAbstractRefreshableConfigApplicationContext{
- publicAbstractXmlApplicationContext(){
- }
- publicAbstractXmlApplicationContext(ApplicationContextparent){
- super(parent);
- }
- //这里是实现loadBeanDefinitions的地方
- protectedvoidloadBeanDefinitions(DefaultListableBeanFactorybeanFactory)throwsIOException{
- //CreateanewXmlBeanDefinitionReaderforthegivenBeanFactory.
- //创建XmlBeanDefinitionReader,并通过回调设置到BeanFactory中去,创建BeanFactory的使用的也是DefaultListableBeanFactory。
- XmlBeanDefinitionReaderbeanDefinitionReader=newXmlBeanDefinitionReader(beanFactory);
- //Configurethebeandefinitionreaderwiththiscontext's
- //resourceloadingenvironment.
- //这里设置XmlBeanDefinitionReader,为XmlBeanDefinitionReader配置ResourceLoader,因为DefaultResourceLoader是父类,所以this可以直接被使用
- beanDefinitionReader.setResourceLoader(this);
- beanDefinitionReader.setEntityResolver(newResourceEntityResolver(this));
- //Allowasubclasstoprovidecustominitializationofthereader,
- //thenproceedwithactuallyloadingthebeandefinitions.
- //这是启动Bean定义信息载入的过程
- initBeanDefinitionReader(beanDefinitionReader);
- loadBeanDefinitions(beanDefinitionReader);
- }
- protectedvoidinitBeanDefinitionReader(XmlBeanDefinitionReaderbeanDefinitionReader){
- }
这个类一直没看明白,跟上下有什么联系吗?
继续研究中。。。够我学一阵的了
PS:我是spring新手,这个类我看是个abstract类啊,那么this指的什么呢?顺便帮我补下java基础^_^
一般来说,在抽象类中使用this 通常是获取的子类吧, 我记得struts1.x的DispatcherAction类也使用过类似的技巧来获取它指定执行的是哪个方法. 附件有我以前自己仿的一个例子,可以下去看看,写得比较简单,只是描述了下大概的实现过程。
5 楼anykey10092009-10-27引用
- publicabstractclassAbstractXmlApplicationContextextendsAbstractRefreshableConfigApplicationContext{
- publicAbstractXmlApplicationContext(){
- }
- publicAbstractXmlApplicationContext(ApplicationContextparent){
- super(parent);
- }
- //这里是实现loadBeanDefinitions的地方
- protectedvoidloadBeanDefinitions(DefaultListableBeanFactorybeanFactory)throwsIOException{
- //CreateanewXmlBeanDefinitionReaderforthegivenBeanFactory.
- //创建XmlBeanDefinitionReader,并通过回调设置到BeanFactory中去,创建BeanFactory的使用的也是DefaultListableBeanFactory。
- XmlBeanDefinitionReaderbeanDefinitionReader=newXmlBeanDefinitionReader(beanFactory);
- //Configurethebeandefinitionreaderwiththiscontext's
- //resourceloadingenvironment.
- //这里设置XmlBeanDefinitionReader,为XmlBeanDefinitionReader配置ResourceLoader,因为DefaultResourceLoader是父类,所以this可以直接被使用
- beanDefinitionReader.setResourceLoader(this);
- beanDefinitionReader.setEntityResolver(newResourceEntityResolver(this));
- //Allowasubclasstoprovidecustominitializationofthereader,
- //thenproceedwithactuallyloadingthebeandefinitions.
- //这是启动Bean定义信息载入的过程
- initBeanDefinitionReader(beanDefinitionReader);
- loadBeanDefinitions(beanDefinitionReader);
- }
- protectedvoidinitBeanDefinitionReader(XmlBeanDefinitionReaderbeanDefinitionReader){
- }
这个类一直没看明白,跟上下有什么联系吗?
继续研究中。。。够我学一阵的了
PS:我是spring新手,这个类我看是个abstract类啊,那么this指的什么呢?顺便帮我补下java基础^_^
相关推荐
《Spring技术内幕:深入解析Spring架构与设计原理(第2版)》从源代码的角度对Spring的内核和各个主要功能模块的架构、设计和实现原理进行了深入剖析。你不仅能从本书中参透Spring框架的出色架构和设计思想,还能从...
《Spring技术内幕:深入解析Spring架构与设计原理(第2版)》这本书主要聚焦于Spring框架的核心架构和技术细节,帮助读者全面理解Spring的工作机制、设计理念以及实现方式。下面将根据书名及其描述来展开相关知识点。 ...
Spring技术内幕:深入解析Spring架构与设计原理 Spring是Java企业应用开发的主要框架之一,其架构和设计原理对Java开发者具有重要影响。本文将深入解析Spring架构和设计原理,对Spring的核心概念、架构设计和关键...
Spring技术内幕 深入解析Spring架构与设计原理1(完整清晰版),一共两部分,这是第一部分 《Spring技术内幕:深入解析Spring架构与设计原理》是Spring领域的问鼎之作,由业界拥有10余年开发经验的资深Java专家亲自...
本书从源代码的角度对Spring的内核和各个主要功能模块的架构、设计和实现原理进行了深入剖析。你不仅能从本书中参透Spring框架的优秀架构和设计思想,还能从Spring优雅的实现源码中一窥Java语言的精髓。本书在开篇...
如果你以一种淡定的心态翻开这本书,无论你是Java程序员、Spring开发者,还是平台开发人员、系统架构师,抑或是对开源软件源代码着迷的代码狂人,都能从《Spring技术内幕:深入解析Spring架构与设计原理》中受益。...
《Spring技术内幕:深入解析Spring架构与设计原理(第2版)》从源代码的角度对Spring的内核和各个主要功能模块的架构、设计和实现原理进行了深入剖析。你不仅能从《Spring技术内幕:深入解析Spring架构与设计原理...
《SPRING技术内幕:深入解析SPRING架构与设计原理》这本书是Java开发领域的一部重量级作品,由具有丰富开发经验的专家撰写,受到了Java开发者社区和Spring开发者社区的高度推崇。书中深入剖析了Spring框架的核心架构...
Spring技术内幕 深入解析Spring架构与设计原理1(完整清晰版),一共两部分,这是第一部分 《Spring技术内幕:深入解析Spring架构与设计原理》是Spring领域的问鼎之作,由业界拥有10余年开发经验的资深Java专家亲自...
《Spring技术内幕 - 深入解析Spring架构与设计原理》这本书是IT领域的经典之作,专为想要深入了解Spring框架的开发者而准备。Spring作为Java领域最广泛应用的轻量级框架,其设计理念和实现机制一直是广大程序员关注...
根据提供的文件标题“Spring技术内幕:深入解析Spring架构与设计原理(第2版)”,我们可以推测这本书主要聚焦于Spring框架的核心架构与设计理念。虽然描述部分为空白,但是结合标题和标签“spring”,我们可以深入...
《Spring技术内幕-深入解析_Spring架构与设计原理》是一本深入探讨Spring框架核心机制与设计理念的专业书籍,由资深软件开发专家计文柯撰写。本书不仅适合Java开发者、Spring框架使用者,也对平台开发人员、系统架构...
《SPRING技术内幕:深入解析SPRING架构与设计原理》这本书深入探讨了Spring框架的核心机制、设计理念以及在实际开发中的应用。Spring作为Java领域最流行的轻量级框架,它的广泛应用和强大功能使得深入理解其工作原理...
深入解析spring架构原理与设计思想,探究spring成功的奥秘。 揭开spring源代码的神秘面纱,展示系统阅读开源软件源代码的方法和秘诀。 掌握spring的架构原理与设计思想真的能让开发者如虎添翼吗? ioc容器...
标题和描述中提到的《SPRING技术内幕_深入解析SPRING架构与设计原理 第2版本》指向了关于Spring框架的技术内幕和设计原理的详细解析。Spring是一个开源的Java平台,它提供了全面的基础设施支持,以便开发者可以创建...