Spring核心技术Spring容器

Spring核心技术

  3709人阅读  评论(14)  收藏  举报
  分类:
 

    这是第二次看关于spring的资料,因为刚开始学习Spring的时候是边看视频边学习的,所以更注重的是实现代码,但是对宏观的掌握还是不够,这次主要从宏观的角度来分析一下Spring。

什么是Spring

    Spring是分层的Java SE/EE应用一站式的轻量级开源框架,以IoC(Inverse of Control:反转控制)和AOP(AspectOriented Programming:面向切面编程)为内核,提供了展现层Spring MVC和持久层Spring JDBC以及业务层事务管理等众多的企业级应用技术,此外,Spring以海纳百川的胸怀整合了开源世界里众多注明的第三方框架的类库,逐渐成为使用最多的JavaEE企业应用开源框架

 

Spring的好处

    首先,既然要学习和使用Spring,那么,我们就必须要知道使用Spring的好处,如果不能了解他的好处,就不能在适当的时候使用这个框架,当然也就失去了学习的意义。

    方便结构,简化开发

    通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编程所造成的过度程序耦合,有了Spring,用户不必再为单实例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。

    AOP编码的支持

    通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付。

    声明式事物的支持

    在Spring中,我们可以从单调烦闷的十五管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。

    方便程序的测试

    可以用非容器以来的编程方式进行几乎所有的测试工作,在Spring里,测试不再是昂贵的操作,而是随手可做的事情。

    方便集成各种优秀框架

    Spring不排斥各种优秀的开源框架,相反,Spring可以降低各种框架的使用难度,Spring提供了对各种优秀框架(如Struts,hibernate,Hessian,Quartz等)的直接支持。

    降低Java EE API的使用难度

    Spring对很多难用的Java EE API(如JDBC,JavaMail,远程调用等)提供了一个薄薄的封装层,通过Spring的简易封装,这些Java EE API的使用难度大为降低。

    Java源码是经典学习范例

    Spring的源码设计精妙、结构清晰、匠心独运,处处体现着大师对Java设计模式灵活运用以及对Java即使的高深造诣,Spring框架源码无疑是Java技术的最佳实践的范例。如果想在段时间内迅速提高自己的Java技术水平和应用开发水平,学习和研究Spring源码将会使你受到意想不到的效果。

 

Spring的体系结构

    如果说Spring是一个人,那么AOP和IoC就是他的灵魂(AOP和IoC在之前博客已经讲到),而他的结构体系就是他的骨骼,所以,这里我们要详细的研究一下Spring的结构体系

一张图胜过千言万语


    下面依次讲讲结构体系中每一个模块的内容

核心容器:

    核心容器组成的核心,Beans,上下文和表达式语言模块,每一块的主要功能为:

    spring  IOC 用配置 loc  BeanFactory Spring 

    Context  BeanFactory  i18n  Bean JNDI  EJB 访

    ApplicationContext Context 

    表达式语言模块 (unified EL) ·使便 Spring IOC 

 

数据访问/集成:

    数据访问/集成层包括JDBC,ORMOXMJMS和事务处理模块,每一个模板的功能如下

    JDBC模块提供了不再需要冗长的JDBC编码相关了JDBC的抽象层。

    ORM模块提供的集成层。流行的对象关系映射API,包括JPAJDOHibernateiBatis

    OXM模块提供了一个支持对象/ XML映射实现对JAXBCastor,使用XMLBeansJiBXXStream 的抽象层。

    Java消息服务JMS模块包含的功能为生产和消费的信息。

    事务模块支持编程和声明式事务管理实现特殊接口类,并为所有的POJO

   任何应用程序,其核心的问题是对数据的访问和操作。数据有很多表现形式,如数据表、XML、消息等,而每种数据形式又拥有不同的数据访问技术(如数据表的访问既可以直接通过JDBC,也可以通过HirnateiBatis)

    Spring站在DAO的抽象层面,建立了一套面向DAO层统一的异常体系,同时将各种访问数据的检查型异常转换为非检查型异常,为整合各种持久层框架提供基础。其次,Spnng通过模板化技术对各种数据访问技术进行了薄层的封装,将模式化的代码隐藏起来,使数据访问的程序得到大幅简化·这样,Spring就建立起了和数据形式及访问技术无关的统一的DAO层,借助AOP技术,Spg提供了声明式事务的功能。

Web:

    在Web层包括网络,Web-ServletWeb-Struts和网络的Portlet组件,其细节如下:

    Web模块提供了基本的Web开发的集成特性,例如多方文件上传功能和使用的servlet监听器的IoC容器初始化和针对Web的应用程序上下文。

    Web-Servlet模块包含Spring的模型-视图-控制器(MVC)实现Web应用程序。

    Web-Struts模块包含支持类内的Spring应用程序集成了经典的StrutsWeb层。yiibai.com

    Web-Portlet模块提供了MVC实现在portlet环境中使用和镜子WebServlet的模块的功能。yiibai.com

 

    该模块建立在ApplicationContext模块块之上,提供了Web应用的各种工具类,如通过ListenerServlet初始化Spring容器,将Sprmg容器注册到Web容器中。其次,该模块还提供了多项面向web的功能,如透明化文件上传、VelocityFreeMarkerXSLT的支持。

    此外,Spring可以整合StrutsWebWorkTapestryWebMVC框架。

 

其他:

    还有像AOP,切面,规范,网络和测试模块,其详细情况如下其他一些重要的模块:

    AOP模块提供了面向方面编程实现,允许您定义方法拦截器和切入点,以干净解耦,实现的功能,应该分开的代码。

    Aspects模块提供与AspectJ的集成这又是一个功能强大且成熟的面向方面编程(AOP)框架。

    Instrumentation模块提供了一定的应用服务器中使用类工具的支持和类加载器实现。

    测试模块支持Spring组件使用JUnitTestNG框架的测试。


此外,Spring在远程访问以及WebService上提供了对很多著名框架的整合。由于Spring框架的扩展性,特别是随着spring框架影响性的扩大,越来越多框架主动地支持Spring框架,让spring框架应用涵盖面越来越宽广。


本博客主要借鉴了《Spring3.X企业开发应用实战》,一本非常系统的讲解Spring的书籍,推荐大家看一下


  3616人阅读  评论(0)  收藏  举报
  分类:
 
  容器是Spring框架的核心,Spring容器就是一个巨大的工厂。Spring容器使用Ioc管理所有组成应用系统的组件。

  spring容器会使用XML解析器读取改属性值,并利用反射来创建该实现类的实例。

 

  Spring有两个核心接口:BeanFactory和ApplicationContext,其中ApplicationContext是BeanFactory的子接口。它们都可以代表Spring容器。Spring容器是生成Bean实例的工厂,并管理容器中的Bean。Bean是Spring管理的基本单元。

 

  创建BeanFactory实例时,必须使用Spring容器管理的Bean详细配置信息(XML配置文件)。XML配置文件通常使用Resource对象传入。
Resource接口是Spring提供的资源访问接口,通过使用该接口,Spring能以简单,透明的方式访问子盘,类路径,已经网络上的资源。

大部分Java EE应用,在启动Web应用时自动加载Application实例。对于独立的应用程序,可通过如下方法来实例化BeanFactory。
1.
 //搜索当前文件路径下的beans.xml文件,创建Resource对象
 InputStreamResource isr = new FileSystemResource("beans.xml");
 //以Resource对象作为参数,创建BeanFactory实例
 XmlBeanFactory factory = new XmlBeanFactory(isr);
2.
 //搜索类加载路径,以类加载路径下的beans.xml文件创建Resource对象
 ClassPathResource res = new ClassPathResource("beans.xml");
 //以Resource对象为参数,创建BeanFactory实例
 XmlBeanFactory factory = new XmlBeanFactory(res);

 

ApplicationContext允许以声明式方式操作容器,无需手动创建它。可利用如ContextLoader得支持类,在Web应用启动时自动创建ApplicationContext。当然,也可以采用编程方式创建ApplicationContext.
除了提供BeanFactory所支持的全部功能外,ApplicationContext还有如下额外功能:
1.ApplicationContext继承MessageSource接口,因此提供国际化支持。
2.资源访问,比如URL和文件
3.事件机制
4.载入多个配置文件。

 

ApplicationContext经常用到的三个实现:

1.ClassPathXmlApplicationContext:从类路径中的XML文件载入上下文定义信息。把上下文定义文件当成类路径资源。

2.FileSystemXmlApplicationContext:从文件系统中的XML文件载入上下文定义信息。

3.XmlWebApplicationContext:从Web系统中的XML文件载入上下文定义信息。

 

BeanFactory延迟加载所有的Bean,知道getBean()方法被调用时,Bean才被创建。

当系统创建ApplicationContext容器时,默认会预初始化所有singleton Bean (prototype类型Bean当需要的时候才会创建)。

Spring框架:Spring容器详解

Spring容器

Spring容器可以帮助你管理所有的Bean对象,专业术语称之为IoC控制反转。在传统的程序中,对象的生成都是由开发者完成的。而在控制反转中,对象的生成全部都交给框架完成。这样的好处就是减少了程序的依赖性。

Bean在Spring中的生命周期如下:

  • 实例化。Spring通过new关键字将一个Bean进行实例化,JavaBean都有默认的构造函数,因此不需要提供构造参数。
  • 填入属性。Spring根据xml文件中的配置通过调用Bean中的setXXX方法填入对应的属性。
  • 事件通知。Spring依次检查Bean是否实现了BeanNameAware、BeanFactoryAware、ApplicationContextAware、BeanPostProcessor、InitializingBean接口,如果有的话,依次调用这些接口。
  • 使用。应用程序可以正常使用这个Bean了。
  • 销毁。如果Bean实现了DisposableBean接口,就调用其destroy方法。

定义一个Bean的语法如下。

<beans xmlns="...">
  <bean id="apple" class="com.whitejava.Apple"/>
</beans>

使用这个Bean时只要通过applicationContext.getBean("apple")即可获取。

作用域。在Spring中还可以指定Bean的作用域,也就是Bean的寿命,只要设置bean标签的scope属性即可。Spring提供的生命周期有:singleton整个应用只有一个、prototype每次调用都产生一个新的、request每个HTTP请求对应一个bean、session每个HTTP会话对应一个bean、global-session每个portlet上下文session对应一个bean。默认生命周期是singleton。

初始化和销毁。第一种方法,在xml中的bean标签增加init-method和destroy-method属性来指定初始化和销毁方法。第二种方法,在bean的java类中implements InitializingBean或者DisposableBean接口实现初始化和销毁。第三种方法,在xml中的beans标签中增加default-init-method和default-destroy-method属性。

另外,可以通过RPC或者JMS配置远程Bean。后面的章节有介绍。

外部配置

有时候有些关键的属性,比如数据库密码,需要放在xml文件之外,便于后续修改。Spring解决这个问题的方法有两种,一种是属性占位符,一种是属性重写。另外阿里提供的AutoConfig有更好的配置管理机制,将在后面详细介绍。

关于占位符,首先载入属性文件:

<context:property-placeholder location="classpath:/db.properties"/>
或者
<context:property-placeholder location="file:///etc/db.properties"/>

引用属性中的变量:

<bean id="dataSource" class="org.springframework.jdbc.datbase.DriverManagerDataSource">
  <property name="driverClassName" value="${jdbc.driverClassName}"/>
  <property name="url" value="${jdbc.url}/>
</bean>

覆盖properties文件中的变量:

<util:properties id="defConf>
  <prop key="jdbc.url">jdbc:mysql://localhost/test</prop>
  <prop key="jdbc.driverClassName">com.mysql.jdbc.Driver</prop>
</util:properties>

<context:property-placeholder location="classpath:/db.properties" properties-ref="defConf" system-properties-mode="OVERRIDE"/>
除了OVERRIDE还有FALLBACK、NEVER。

覆盖xml配置。载入properties文件并覆盖现有的xml配置。请看下面的例子:

<bean id="dataSource" class="xxx">
  <property name="url">jdbc:oracle://xxx</property>
  <property name="username">xxx</property>
</bean>

<context:property-overrider location="classpath:/db.properties"/>

db.properties文件的内容:

dataSource.url=jdbc:mysql://xxx
dataSource.username=yyy

加密配置值。载入经过加密的properties文件:

<bean id="environmentConfig" class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig">
  <property name="algorithm" value="PBEWithMD5AndDES"/>
  <property name="passwordEnvName" value="DB_ENCRYPTION_PWD"/>
</bean>

<bean id="stringEncrypter" class="org.jasypt.encryption.pbe.Environment">
  <property name="config-ref" ref="environmentConfig"/>
</bean>

<bean id="org.jasypt.spring.properties.EncryptablePropertyPlaceholderConfigurer">
  <constructor-arg ref="stringEncrypter"/>
</bean>
Session

Spring中的Session一般不需要直接操作,而是将数据保存到Bean容器中的scope=session中。

剖析Spring容器的作用及实现方式  

2008-11-05 20:25:00|  分类: java技术|举报|字号 订阅

     们在使用ssh整合项目的时候,Spring在其中是一个非常重要的框架,它在其中可以说是一个最核心的框架,提到spring我们不得不提它的IOC容器的功能了!它是一个大工厂,可以在其中产生和管理很多的bean,下面,请随阿堂一起来好好看看spring的容器功能方面的介绍,这对于我们在解决ssh框架整合中的问题,进行测试时是非常有用的!

1.spring容器
     Spring有两个核心接口BeanFactory和ApplicationContext,其中ApplicationContext是BeanFactory的子接口,它们代表了Spring容器,Spring容器是产生Bean的工厂,用于管理容器中的Bean。Bean是Spring管理的基本单位,在spring的J2EE应用中,所有的组件都是Bean。Bean包括数据源、Hibernate的SessionFactory、事务管理器等。

     应用中的所有组件,都处于spring的管理下,都被spring以Bean的方式管理,spring负责创建Bean实例,并管理其生命周期。Spring里的Bean是非常广义的概念,任何Java对象和Java组件都被当成Bean处理,甚至这些组件,并不是标准的JAVABEAN。
     Bean在spring容器中运行,无须感受Spring容器的存在,一样可以接受spring的信赖注入,包括Bean属性的注入、合作者的注入、信赖关系的注入等。
spring容器负责创建Bean实例,所以需要知道每个Bean的实现类,JAVA程序的实现面向接口编程,无须关心Bean实例的实现。但Spring容器必须能精确知道每个Bean的实现类,因此Spring配置文件必须精确配置Bean的实现类。

 

    Spring容器最基本的接口就是BeanFactory. BeanFactory负责配置、创建、管理Bean,它有一个子接口ApplicationContext,因此也称为Spring上下文。Spring容器负责管理Bean与Bean之间的信赖关系。

BeanFactory接口包含如下基本的方法:
public boolean containsBean(String name),判断Spring容器是否包含id为name的Bean定义
public Object getBean(String name)返回容器id为name的bean
public Object getBean(String name,Class requiredType)返回容器中id为name,并且类型为requiredType的Bean
public Class getType(String name)返回容器中id为name的Bean的类型

    调用者只需使用getBean方法即可获得指定Bean的引用,无须关心Bean的实例化过程,即Bean实例的创建过程完全透明。

    BeanFactory有很多实现类,通常使用org.springframework.beans.factory.xml.XmlBeanFactory类。但对于大部分J2EE应用而言,推荐使用ApplicationContext. ApplicationContext是BeanFactory的子接口,其常用实现类是

org.springframework.context.support.FileSystemXmlApplicationContext和

org.springframework.context.support.ClassXmlAplicationContext.

     创建 BeanFactory实例时,必须提供Spring容器管理的Bean的详细配置信息。 Springr的配置信息通常采用XML配置文件来设置,因此,创建BeanFactory实例时,应该提供XML配置文件作为参数。 XML配置文件通常使用Resource对象传入

 

Resource接口用于访问配置文件资源
     大部分j2ee应用,可在启动web应用时自动加载ApplicationContext实例,接受Spring管理的Bean无须知道ApplicationContext的存在,一样可以利用ApplicationContext的管理。

对于独立的应用程序,也可以通过如下方法来实例化BeanFactory

 

//搜索当前文件路径下的beans.xml文件创建Resource对象
InputStreamResource isr=new FileSystemResource(is);
//以Resource对象作为参数,创建BeanFactory的实例
XmlBeanFactory factory=new XmlBeanFactory(isr);

 

或者采用如下方法


//搜索CLASSPATH路径,以CLASSPATH路径下的beans.xml文件创建Resource对象
ClassPathResource res=new ClassPathResource("beans.xml");
//以Resource 对象作为参数,创建BeanFactory实例
XmlBeanFactory factory=new XmlBeanFactory(res);

 

     如果应用里有多个属性配置文件,则应该采用BeanFactory的子接口ApplicationContext来创建BeanFactory的实例,ApplicationContext通常采用如下两个实现类。

FileSystemXmlApplicationContext ,以指定路径的XML配置文件创建ApplicationContext
ClassPathXmlApplicationContext,以CLASSPATH路径下的XML配置文件创建ApplicationContext

 

如果需要同时加载多个XML配置文件,可以采用如下方式

//搜索CLASSPATH路径,以CLASSPATH路径下的applicationContext.xml 和 service.xml文件创建ApplicationContext
ClassPathXmlApplicationContext appContext=new ClassPathXmlApplicationContext(
 new String[] {"applicationContext.xml","service.xml"});

//事实上,ApplicationContext是BeanFactory的子接口,支持强制类型转换
BeanFactory factory=(BeanFactory) appContext;

 

当然,也可以支持从指定的路径来搜索特定文件加载:


//以指定路径下的applicationContext.xml和service.xml文件创建 Applicationcontext
FileSystemXmlAplicationContext appContext=new
FileSystemXmlApolicationContext(
 new String[] {"applicationContext.xml","service.xml"}
)
//事实上,ApplicationContext是BeanFactory的子接口,支持强制类型转换
BeanFactory factory=(BeanFactory) appContext;


2.使用ApplicationContext
    很多时候,并不是直接使用BeanFactory实例作为Spring容器,而是使用ApplicationContext实例。因此,有时候也称Spring容器为Spring上下文。 ApplicationContext是BeanFactory接口的子接口,它增强了BeanFactory的功能。
    ApplicationContext允许以声明方式操作容器,无须手动创建它。可利用如ContextLoader的支持类,在web应用启动自动创建ApplicationContext。当然,也可以采用编程方式创建ApplicationContext

 

ApplicationContext继承MessageSource接口,因此提供国际化支持资源访问,比如 URL和文件
事件传递
载入多个配置文件

    ApplicationContext包括  BeanFactory的全部功能,因此建议优先使用ApplicationContext ,除了对于某些内存非常关键的作用,才考虑使用BeanFactory

以下是个人对spring使用过程中几个常用概念的感性理解,也许和书面的定义不一样,但是个人觉得理解这样的概念,越简单越感性越让开发人员,特别是初学者理解更容易。而不至于刚接触就被那些复杂描述的概念所吓倒:)

一:IOC控制反转
public class PersonServiceBean{
private PersonDao personDao = new PersonDaoBean();

public save(Person person){
personDao.save(person);
}
}
PersonDaoBean是在应用内部创建及维护。所谓控制反转就是应用本身不负责对象的创建及维护,
依赖对象的创建及维护是由外部容器负责的。这样控制权就由应用转移到了外部容器,控制权的
转移就是所谓的反转。

二:依赖注入(Dependency Injection)
当我们把依赖对象交给外部容器负责创建,那么PersonServiceBean可以改成如下:
public class PersonServiceBean{
private PersonDao personDao;
//通过构造器参数,让容器把创建好的依赖对象注入进PersonServiceBean,当然也可以通
//过setter方法进行注入
public PersonServiceBean(PersonDao personDao){
this.personDao = personDao;
}
public save(Person person){
personDao.save(person);
}
}
所谓依赖注入就是指:在运行期,由外部容器动态的将依赖对象注入到组件中。

三:为什么要使用spring
1:降低软件之间的耦合度,实现软件各层之间的解耦;
Controller -> Service -> DAO
2:可以使用spring容器提供的各项服务;(如:事务管理、JMS服务、Spring Code 核心服务、持久化服务、其他)
3:容器提供单例模式的支持,开发人员不需要自己编写实现单例代码;
4:容器提供AOP技术,利用它很容易实现如权限拦截、运行期监控等功能;
5:容器提供很多辅助类,使用这些类能够加快应用的开发,如:JdbcTemplate、HibernateTemplate等
6:spring对主流的应用框架提供了集成支持,如:集成Hibernate、JPA、Struts等,这样便于应用的开发

四:关于经常说到的一些概念
1:轻量级和重量级的概念划分
轻量级和重量级的划分,主要看它使用了多少服务。使用的服务越多,容器为普通java对象做的工作也
越多,必然会影响到应用的发布时间或者是运行性能。
对于spring容器,它提供了很多服务,但是这些服务并不是默认为应用打开的,应用需要某种服务,还需要指明
应用该服务,如果应用服务很少,如:只使用了spring核心服务,我们就可以认为此时应用属于轻量级应用,反之就
属于重量级。目前EJB容器因为它默认为应用提供了EJB规范的所有服务,所以它属于重量级的。

五:依赖注入方式
1、使用构造器注入
2、使用属性setter方法注入
3、使用filed注入(用于注解方式)

spring IOC容器实现探讨

Posted on 2007-04-20 11:59  dennis 阅读(13126)  评论(12)   编辑   收藏 所属分类:  源码解读 
    spring IOC容器的实现,一开始我被复杂的接口和类所掩埋,看不清整体的思路和设计,踟蹰于代码丛林中,摸不清前进的方向。一开始我就决定只研读以xml文件做配置文件的XmlFactoryBean的具体实现为主要目标,渐渐地有了点感觉,用UML把spring中的bean工厂体系展现出来之后就更清晰了,让你不得不感叹设计的精巧和复杂。本文只是我个人对spring IOC实现的理解,如有错误,请不吝赐教,谢谢。
    首先,需要理解的是spring容器中bean的生命周期,《spring in action》中的那张图是最好的解释,结合这张图和源码来解读spring中IOC的实现将非常容易理解。这张图完整展示了spring容器中一个bean从创建到销毁的整个生命周期。
    
1. 容器寻找Bean的定义信息并且将其实例化。
2.受用依赖注入,Spring按照Bean定义信息配置Bean的所有属性。
3.如果Bean实现了BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。
4.如果Bean实现了BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身。
5.如果BeanPostProcessor和Bean关联,那么它们的postProcessBeforeInitialzation()方法将被调用。
6.如果Bean指定了init-method方法,它将被调用。
7.最后,如果有BeanPsotProcessor和Bean关联,那么它们的postProcessAfterInitialization()方法将被调用。
    到这个时候,Bean已经可以被应用系统使用了,并且将被保留在Bean Factory中知道它不再需要。有两种方法可以把它从Bean Factory中删除掉。
1.如果Bean实现了DisposableBean接口,destory()方法被调用。
2.如果指定了订制的销毁方法,就调用这个方法。
    
    下面我们将会看到,这些bean创建销毁的每个阶段是如何在源码中实现的。
    再看看spring中bean工厂的完整体系,比较复杂,不过我们只需要关注其中的几个核心工厂。
      
    (看不清楚,请 下载图片来看,比较清晰)
    这些工厂类没有在同一个包内,分布在org.springframework.beans以及它的子包内,把它们放在一起就看的比较清楚了。我们需要关注的是这么两个类:org.springframework.beans.factory.support.AbstractBeanFactory 
org.springframework.beans.factory.support.DefaultListableBeanFactory 
以及接口:
org.springframework.beans.factory.support.BeanDefinitionRegistry 

    AbstractBeanFactory作为BeanFactory接口的抽象实现类,是其他工厂类的父类,提供了bean的singlton缓存、singleton/prototype的决定、bean的别名以及bean和它的子类bean的定义合并(bean definition merging for child bean definitions)和销毁。这里有3个重载的getBean方法(实现BeanFactory定义的getBean方法),我们关注下最主要的这个方法:
public Object getBean(String name, Class requiredType, Object[] args)  throws BeansException {
        String beanName = transformedBeanName(name);
        Object bean =  null;

         //  Eagerly check singleton cache for manually registered singletons.
        Object sharedInstance =  null;
         // 从单例缓存中获取
         synchronized ( this.singletonCache) {
            sharedInstance =  this.singletonCache.get(beanName);
        }
         if (sharedInstance !=  null) {
             if (isSingletonCurrentlyInCreation(beanName)) {
                 if (logger.isDebugEnabled()) {
                    logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                            "' that is not fully initialized yet - a consequence of a circular reference");
                }
            }
             else {
                 if (logger.isDebugEnabled()) {
                    logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }
            bean = getObjectForSharedInstance(name, sharedInstance);
        }

         else {
             //  Fail if we're already creating this singleton instance:
            
//  We're assumably within a circular reference.
             if (isSingletonCurrentlyInCreation(beanName)) {
                 throw  new BeanCurrentlyInCreationException(beanName);
            }

             //  Check if bean definition exists in this factory.
            
// 检测bean是否定义在父工厂
             if (getParentBeanFactory() !=  null && !containsBeanDefinition(beanName)) {
                 //  Not found -> check parent.
                 if (getParentBeanFactory()  instanceof AbstractBeanFactory) {
                     //  Delegation to parent with args only possible for AbstractBeanFactory.
                     return ((AbstractBeanFactory) getParentBeanFactory()).getBean(name, requiredType, args);
                }
                 else  if (args ==  null) {
                     //  No args -> delegate to standard getBean method.
                     return getParentBeanFactory().getBean(name, requiredType);
                }
                 else {
                     throw  new NoSuchBeanDefinitionException(beanName,
                            "Cannot delegate to parent BeanFactory because it does not supported passed-in arguments");
                }
            }

             // 获取BeanDefinition
            RootBeanDefinition mergedBeanDefinition = getMergedBeanDefinition(beanName,  false);
            checkMergedBeanDefinition(mergedBeanDefinition, beanName, requiredType, args);

             //  Create bean instance.
            
// 创建bean,如果为为singleton
             if (mergedBeanDefinition.isSingleton()) {
                 synchronized ( this.singletonCache) {
                     //  Re-check singleton cache within synchronized block.
                    sharedInstance =  this.singletonCache.get(beanName);
                     if (sharedInstance ==  null) {
                         if (logger.isDebugEnabled()) {
                            logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
                        }
                         this.currentlyInCreation.add(beanName);
                         try {
                            sharedInstance = createBean(beanName, mergedBeanDefinition, args);
                            //加进单例缓存
                            addSingleton(beanName, sharedInstance);
                        }
                         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.
                            destroyDisposableBean(beanName);
                             throw ex;
                        }
                         finally {
                             this.currentlyInCreation.remove(beanName);
                        }
                    }
                }
                bean = getObjectForSharedInstance(name, sharedInstance);
            }
             // 如果是prototype
             else {
                 //  It's a prototype -> create a new instance.
                bean = createBean(beanName, mergedBeanDefinition, args);
            }
        }

         //  Check if required type matches the type of the actual bean instance.
         if (requiredType !=  null && !requiredType.isAssignableFrom(bean.getClass())) {
             throw  new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
         return bean;
    }
    当你调用getBean获取一个bean的时候,spring首先查找单例缓存中是否已经有这个bean,有的话直接返回(首先会判断是否已经创建),如果没有,spring就开始创建这个bean:首先获取bean的定义(BeanDefinition),检测bean是否定义在父工厂中,有的话调用父工厂的getBean方法;没有就检测bean是singleton还是prototype,如果是singleton就是创建bean并加入缓存以便下次直接调用,如果是prototype,就在每次调用时重新创建一个bean实例。注意createBean(beanName, mergedBeanDefinition, args); 这个方法,这是创建bean的核心方法,并且是一个abstract方法,将被子类实现。
    看看是如何获取bean的定义的,
protected RootBeanDefinition getMergedBeanDefinition(String name,  boolean includingAncestors)
         throws BeansException {

        String beanName = transformedBeanName(name);

         //  Efficiently check whether bean definition exists in this factory.
         if (includingAncestors && !containsBeanDefinition(beanName) &&
                getParentBeanFactory()  instanceof AbstractBeanFactory) {
             return ((AbstractBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(beanName,  true);
        }

         //  Resolve merged bean definition locally.
         return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
    }

    调用重载的getMergedBeanDefinition合并父工厂和子工厂中的bean定义,注意getBeanDefinition(beanName),这是一个抽象方法,延迟到子类实现以便提供获取bean定义的具体方法,这个方法和 createBean 一样都是template method模式的应用。看看它们的定义:
protected  abstract BeanDefinition getBeanDefinition(String beanName)  throws BeansException;

protected  abstract Object createBean(
            String beanName, RootBeanDefinition mergedBeanDefinition, Object[] args)  throws BeanCreationException;
  
    基本了解了AbstractBeanFactory 后,我们来看看它的子类的AbstractAutowireCapableBeanFactory ,这个类实现了createBean() ,在这个方法中我们将看到与 上面bean的生命周期图对应的 bean的创建过程,英文注释已经非常清楚:
protected Object  createBean(String beanName, RootBeanDefinition mergedBeanDefinition, Object[] args)
             throws BeanCreationException {

         if (logger.isDebugEnabled()) {
            logger.debug("Creating instance of bean '" + beanName +
                    "' with merged definition [" + mergedBeanDefinition + "]");
        }

        Object bean =  null;

         //  Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
         if (mergedBeanDefinition.hasBeanClass()) {
            bean =  applyBeanPostProcessorsBeforeInstantiation(mergedBeanDefinition.getBeanClass(), beanName);
             if (bean !=  null) {
                 return bean;
            }
        }

         //  Guarantee initialization of beans that the current one depends on.
         if (mergedBeanDefinition.getDependsOn() !=  null) {
             for ( int i = 0; i < mergedBeanDefinition.getDependsOn().length; i++) {
                getBean(mergedBeanDefinition.getDependsOn()[i]);
            }
        }

        BeanWrapper instanceWrapper =  null;
        Object originalBean =  null;
        String errorMessage =  null;

         try {
             //  Instantiate the bean.
            errorMessage = "Instantiation of bean failed";

             if (mergedBeanDefinition.getFactoryMethodName() !=  null)  {
                instanceWrapper =  instantiateUsingFactoryMethod(beanName, mergedBeanDefinition, args);
            }
             else  if (mergedBeanDefinition.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
                    mergedBeanDefinition.hasConstructorArgumentValues() )  {
                instanceWrapper = autowireConstructor(beanName, mergedBeanDefinition);
            }
             else {
                 //  No special handling: simply use no-arg constructor.
                instanceWrapper =  instantiateBean(beanName, mergedBeanDefinition);
            }
            bean = instanceWrapper.getWrappedInstance();

             //  Eagerly cache singletons to be able to resolve circular references
            
//  even when triggered by lifecycle interfaces like BeanFactoryAware.
             if (isAllowCircularReferences() && isSingletonCurrentlyInCreation(beanName)) {
                 if (logger.isDebugEnabled()) {
                    logger.debug("Eagerly caching bean with name '" + beanName +
                            "' to allow for resolving potential circular references");
                }
                addSingleton(beanName, bean);
            }

             //  Initialize the bean instance.
            errorMessage = "Initialization of bean failed";
             populateBean(beanName, mergedBeanDefinition, instanceWrapper);

             if (bean  instanceof  BeanNameAware) {
                 if (logger.isDebugEnabled()) {
                    logger.debug("Invoking setBeanName on BeanNameAware bean '" + beanName + "'");
                }
                ((BeanNameAware) bean).setBeanName(beanName);
            }

             if (bean  instanceof  BeanFactoryAware) {
                 if (logger.isDebugEnabled()) {
                    logger.debug("Invoking setBeanFactory on BeanFactoryAware bean '" + beanName + "'");
                }
                ((BeanFactoryAware) bean).setBeanFactory( this);
            }

            originalBean = bean;
            bean =  applyBeanPostProcessorsBeforeInitialization(bean, beanName);
            invokeInitMethods(beanName, bean, mergedBeanDefinition);
            bean =  applyBeanPostProcessorsAfterInitialization(bean, beanName);
        }
         catch (BeanCreationException ex) {
             throw ex;
        }
         catch (Throwable ex) {
             throw  new BeanCreationException(
                    mergedBeanDefinition.getResourceDescription(), beanName, errorMessage, ex);
        }

         //  Register bean as disposable, and also as dependent on specified "dependsOn" beans.
         registerDisposableBeanIfNecessary(beanName, originalBean, mergedBeanDefinition);

         return bean;
    }
    通过instanceof操作符来判断bean是否实现了用于生命周期回调的接口,然后调用相应的回调方法,可以看到spring充分实践了针对接口编程的原则,虽然很夸张的一个方法一个接口的地步,不过这些接口也是作为mark interface用于标记回调。结合上面的生命周期图看这段代码将很好理解。有了bean的创建方法,那么如何获取bean在配置文件中的定义信息呢?也就是在哪里实现了 getBeanDefinition方法呢?答案就在AbstractAutowireCapableBeanFactory 的子类DefaultListableBeanFactory中。

    DefaultListableBeanFactory 不仅继承了AbstractAutowireCapableBeanFactory ,还实现了BeanDefinitionRegistry和ConfigurableListableBeanFactory接口。其中ConfigurableListableBeanFactory接口是定义了分析和修改bean定义信息的回调方法,暂时不去管它。看看BeanDefinitionRegistry接口:
public  interface BeanDefinitionRegistry {
   int getBeanDefinitionCount();
  String[] getBeanDefinitionNames();
  BeanDefinition getBeanDefinition(String beanName)  throws NoSuchBeanDefinitionException;
  String[] getAliases(String beanName)  throws NoSuchBeanDefinitionException;
   void registerAlias(String beanName, String alias)  throws BeansException;
   void  registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
             throws BeansException;
  ......
}

一系列用于获取bean定义信息的方法,这个接口我们将在后面的代码中看到,作为一个mark inteface。注意咯,这个接口中非常关键的一个方法就是registerBeanDefinition,这个方法用于向bean工厂注册解析的每个bean定义,我们将在xml文件的解析的环节看到调用这个方法注册bean定义信息。

    DefaultListableBeanFactory实现了BeanDefinitionRegistry  接口,可以看到它实现了关键的registerBeanDefinition用于将bean的定义注册到工厂类中,其中维护了一个Map用于存储bean的定义信息:
public  void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
             throws BeanDefinitionStoreException {

        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "Bean definition must not be null");

         if (beanDefinition  instanceof AbstractBeanDefinition) {
             try {
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
             catch (BeanDefinitionValidationException ex) {
                 throw  new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }

        Object oldBeanDefinition =  this.beanDefinitionMap.get(beanName);
         if (oldBeanDefinition !=  null) {
             if (!isAllowBeanDefinitionOverriding()) {
                 throw  new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                        "': there's already [" + oldBeanDefinition + "] bound");
            }
             else {
                 if (logger.isInfoEnabled()) {
                    logger.info("Overriding bean definition for bean '" + beanName +
                            "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
            }
        }
         else {
             this.beanDefinitionNames.add(beanName);
        }
         this .beanDefinitionMap.put(beanName, beanDefinition);

         //  Remove corresponding bean from singleton cache, if any.
        
//  Shouldn't usually be necessary, rather just meant for overriding
        
//  a context's default beans (e.g. the default StaticMessageSource
        
//  in a StaticApplicationContext).
        removeSingleton(beanName);
    }
    beanDefinitionMap就是我们存储工厂类中注册的bean的信息,用bean name做为key:
/**  Map of bean definition objects, keyed by bean name  */
     private  final Map beanDefinitionMap =  new HashMap();
 
    DefaultListableBeanFactory 重写了
protected  abstract BeanDefinition getBeanDefinition(String beanName)  throws BeansException;
模板方法用于提供bean定义信息给getBean方法用于创建bean实例。getBeanDefinition的从beanDefinitionMap 查找bean定义即可:
public BeanDefinition getBeanDefinition(String beanName)  throws NoSuchBeanDefinitionException {
         BeanDefinition bd  = (BeanDefinition)  this .beanDefinitionMap.get(beanName);
         if (bd ==  null) {
             if (logger.isDebugEnabled()) {
                logger.debug("No bean named '" + beanName + "' found in " + toString());
            }
             throw  new NoSuchBeanDefinitionException(beanName);
        }
         return bd;
    }

    看到了这里是不是觉的有点糊涂,我还是建议有兴趣地找来spring1.2的源码来看看就很清晰了,充分利用eclipse的F3跳转结合上面的那张UML图。
    OK,有了注册bean定义信息的方法(registerBeanDefinition),有了获取bean定义信息的方法(getBeanDefinition ),有了创建bean的方法(createBean),那么在哪里调用这些方法呢?createBean我们已经知道是在BeanFactory的getBean方法时调用,getBeanDefinition 又是在creatBean时调用用于获取bean的定义信息,那么注册bean定义信息的方法肯定是在xml文件解析阶段被调用。
   XmlBeanFactory继承DefaultListableBeanFactory ,没有定义新的方法,只是有两个重载的构造函数:
  
public  class XmlBeanFactory  extends DefaultListableBeanFactory {
   private  final XmlBeanDefinitionReader reader =  new XmlBeanDefinitionReader( this);
   public XmlBeanFactory(Resource resource)  throws BeansException {
         this(resource,  null);
    }
   public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory)  throws BeansException {
         super(parentBeanFactory);
         this.reader. loadBeanDefinitions(resource);
    }
}

    初始化XmlBeanFactory时调用XmlBeanDefinitionReader读取xml配置文件,而XmlBeanDefinitionReader的loadBeanDefinitions方法,载入xml文件并且调用XmlBeanDefinitionParser 解析xml文件同时注册bean定义信息到bean工厂,这几个类的协作以及它们继承体系也非常清晰,在此不再详述(累啊),XmlBeanDefinitionParser是一个接口,具体的实现类是org.springframework.beans.factory.xml.DefaultXmlBeanDefinitionParser,我们关注的就是它是怎么注册bean信息到bean工厂的:
protected  int parseBeanDefinitions(Element root)  throws BeanDefinitionStoreException {

    
     if (IMPORT_ELEMENT.equals(node.getNodeName())) {
                    importBeanDefinitionResource(ele);
                }
                 else  if (ALIAS_ELEMENT.equals(node.getNodeName())) {
                    String name = ele.getAttribute(NAME_ATTRIBUTE);
                    String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
                     this.beanDefinitionReader.getBeanFactory().registerAlias(name, alias);
                }
                 else  if (BEAN_ELEMENT.equals(node.getNodeName())) {
                    beanDefinitionCount++;
                    BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele,  false);
                     // 关键代码,调用工具类将bean定义注册到beanFactory
                     BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,  this .beanDefinitionReader.getBeanFactory());
                }
   
}
工具类BeanDefinitionReaderUtils中的注册方法:
     public  static  void registerBeanDefinition(
            BeanDefinitionHolder bdHolder, BeanDefinitionRegistry beanFactory)  throws BeansException {

         //  Register bean definition under primary name.,注册bean
        beanFactory. registerBeanDefinition(bdHolder.getBeanName(), bdHolder.getBeanDefinition());

         //  Register aliases for bean name, if any.,注册别名
         if (bdHolder.getAliases() !=  null) {
             for ( int i = 0; i < bdHolder.getAliases().length; i++) {
                beanFactory.registerAlias(bdHolder.getBeanName(), bdHolder.getAliases()[i]);
            }
        }
    }
   注意这里的beanFactory是BeanDefinitionRegistry类型 ,DefaultListableBeanFactory实现了这个接口。
    更多内容,比如spring是怎么把bean的属性注入的?答案在BeanWrapperImpl中的一系列setPropertyXXX方法。BeanFactory是如何实例化bean的呢?具体展开请看org.springframework.beans.factory.support.InstantiationStrategy 接口,一个典型的策略模式的应用,两个实现类:SimpleInstantiationStrategy和CglibSubclassingInstantiationStrategy。我们知道spring有3种注入方式:setter、构造函数以及Method Inject。这里的CglibSubclassingInstantiationStrategy使用cglib库用于实现method inject。这样一篇小文容不下这么多内容,还是有兴趣的自己找源码读读。

    写到这里,我对自己的文字表达能力产生怀疑,我能不能把这些所有的信息都说清楚呢?感觉很不满意,将就吧,也算是自己的学习总结。
    读spring源码这段时间,最深的几点体会:
1)单元测试非常重要,充分感受到了单元测试作为项目文档的优势。看不懂一个类,找到这个类的测试类就OK!
2)针对接口编程的原则,spring处处体现了这个原则,繁多的接口带来的是松耦合、高内聚并且易于扩展的架构,但也带来了一定的理解难度。作为通用型框架也许需要这么考虑,在实际项目中的取舍还是要自己把握。
3)设计模式的使用,spring中应用了很多模式,比如template method,比如strategy和factory method、visitor、singleton等,简直是一本模式实践的良好教材。

 
    





  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值