org.springframework.beans及org.springframework.context包是Spring IoC容器的基础。BeanFactory提供的高级配置机制,使得管理任何性质的对象成为可能。ApplicationContext是BeanFactory的扩展,功能获得了进一步加强,好比更易与Spring AOP集成、消息资源处理(国际化处理)、事件传递及各类不一样应用层的context实现(如针对web应用的WebApplicationContext)。html
简而言之,BeanFactory提供了配制框架及基本功能,而ApplicationContext则增长了更多支持企业核心内容的功能。ApplicationContext彻底由BeanFactory扩展而来,于是BeanFactory所具有的能力和行为也适用于ApplicationContext。web
org.springframework.beans.factory.BeanFactory是Spring IoC容器的实际表明者,IoC容器负责容纳此前所描述的bean,并对bean进行管理。spring
在Spring中,BeanFactory是IoC容器的核心接口。它的职责包括:实例化、定位、配置应用程序中的对象及创建这些对象间的依赖。api
Spring为咱们提供了许多易用的BeanFactory实现,XmlBeanFactory就是最经常使用的一个。该实现将以XML方式描述组成应用的对象以及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个彻底可配置的系统或应用。数组
Spring IoC 容器app
从上图能够看到,Spring IoC容器将读取配置元数据;并经过它对应用中各个对象进行实例化、配置以及组装。一般状况下咱们使用简单直观的XML来做为配置元数据的描述格式。在XML配置元数据中咱们能够对那些咱们但愿经过Spring IoC容器管理的bean进行定义。框架
在大多数的应用程序中,并不须要用显式的代码去实例化一个或多个的Spring IoC容器实例。例如,在web应用程序中,咱们只须要在web.xml中添加(大约)8 行简单的XML描述符便可。你能够象下面那样使用ContextLoaderListener来注册一个ApplicationContext:函数
<context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener><!-- or use the ContextLoaderServlet instead of the above listener<servlet> <servlet-name>context</servlet-name> <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> -->
Spring IoC容器至少包含一个bean定义,但大多数状况下会有多个bean定义。当使用基于XML的配置元数据时,将在顶层的<beans/>元素中配置一个或多个<bean/>元素。ui
bean定义与应用程序中实际使用的对象一一对应。一般状况下bean的定义包括:服务层对象、数据访问层对象(DAO)、相似Struts Action的表示层对象、Hibernate SessionFactory对象、JMS Queue对象等等。项目的复杂程度将决定bean定义的多寡。this
如下是一个基于XML的配置元数据的基本结构:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/ spring-beans-2.0.xsd"> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <!-- more bean definitions go here... --></beans>
Spring IoC容器的实例化很是简单,以下面的例子: Resource resource = new FileSystemResource("beans.xml"); BeanFactory factory = new XmlBeanFactory(resource);... 或...ClassPathResource resource = new ClassPathResource("beans.xml"); BeanFactory factory = new XmlBeanFactory(resource);... 或...ApplicationContext context = new ClassPathXmlApplicationContext( new String[] {"applicationContext.xml", "applicationContext-part2.xml"}); // of course, an ApplicationContext is just a BeanFactoryBeanFactory factory =(BeanFactory) context; 将XML配置文件分拆成多个部分是很是有用的。 为了加载多个XML文件生成一个ApplicationContext实例,能够将文件路径做为字符串数组传给ApplicationContext 构造器。而bean factory将经过调用bean defintion reader从多个文件中读取bean定义。一般状况下, Spring团队倾向于上述作法,由于这样各个配置并不会查觉到它们与其余配置文件的组合。 另一种方法是使用一个或多个的<import/>元素来从另一个或多个文件加载bean定义。 全部的<import/>元素必须放在<bean/>元素以前以完成bean定义的导入。 让咱们看个例子: <beans><import resource="services.xml"/> <import resource="resources/messageSource.xml"/> <import resource="/resources/themeSource.xml"/> <bean id="bean1" class="..."/> <bean id="bean2" class="..."/> </beans> 在上面的例子中,咱们从3个外部文件:services.xml、messageSource.xml及themeSource.xml 来加载bean定义。这里采用的都是相对路径,所以,此例中的services.xml必定要与导入文件放在同一目录或类路径, 而messageSource.xml和themeSource.xml的文件位置必须放在导入文件所在目录下的resources目录中。 正如你所看到的那样,开头的斜杠‘/’实际上可忽略。所以不用斜杠‘/’可能会更好一点。 根据Spring XML配置文件的Schema(或DTD),被导入文件必须是彻底有效的XML bean定义文件, 且根节点必须为<beans/> 元素。诚如此前所言,Spring IoC容器将管理一个或多个bean, 这些bean将经过配置文件中的bean定义被建立(在XML格式中为<bean/>元素)。 在容器内部,这些bean定义由BeanDefinition 对象来表示,该定义将包含如下信息 :全限定类名:这一般就是已定义bean的实际实现类。若是经过调用static factory方法来实例化bean, 而不是使用常规的构造器,那么类名称实际上就是工厂类的类名。bean行为的定义,即建立模式(prototype仍是 singleton)、自动装配模式、依赖检查模式、初始化以及销毁方法。这些定义将决定bean在容器中的行为用于 建立bean实例的构造器参数及属性值。好比使用bean来定义链接池,能够经过属性或者构造参数指定链接数, 以及链接池大小限制等。bean之间的关系,即协做 (或者称依赖)。上述内容直接被翻译为每一个bean定义包含的一组 properties除了经过bean定义来描述要建立的指定bean的属性以外,某些BeanFactory的实现也容许将那些 非BeanFactory建立的、已有的用户对象注册到容器中,好比使用DefaultListableBeanFactory的 registerSingleton(..) 方法。 不过大多数应用仍是采用元数据定义为主。命名beanbean的命名采用标准的 Java命名约定,即小写字母开头,首字母大写间隔的命名方式。如accountManager、 accountService、 userDao及loginController,等等。 对bean采用统一的命名约定将会使配置更加简单易懂。并且在使用Spring AOP时, 若是要发通知(advice)给与一组名称相关的bean时,这种简单的命名方式将会令你受益不浅。 每一个bean都有一个或多个id(或称之为标识符或名称,在术语上能够理解成一回事)。 这些id在当前IoC容器中必须惟一。若是一个bean有多个id, 那么其余的id在本质上将被认为是别名。当使用基于XML的配置元数据时,将经过id或name属性来指定bean标识符。 id属性具备惟一性,并且是一个真正的XML ID属性,所以其余xml元素在引用该id时,能够利用XML解析器的验证功能。 一般状况下最好为bean指定一个id。 尽管XML规范规定了XML ID命名的有效字符,可是bean标识符的定义不受该限制, 由于除了使用指定的XML字符来做为id,还能够为bean指定别名,要实现这一点能够在name属性中使用逗号、冒号或者空格 将多个id分隔。值得注意的是,为一个bean提供一个name并非必须的,若是没有指定,那么容器将为其生成一个唯一的 name。对于不指定name属性的缘由咱们会在后面介绍(好比内部bean就不须要)。 bean的别名在对bean进行定义时,除了 使用id属性来指定名称以外,为了提供多个名称,须要经过alias属性来加以指定。而全部的这些名称都指向同一个bean, 在某些状况下提供别名很是有用,好比为了让应用的每个组件能更容易的对公共组件进行引用。然而,在定义bean时就指 定全部的别名并非老是恰当的。有时咱们指望能在当前位置为那些在别处定义的bean引入别名。 在XML配置文件中,可用单独的<alias/> 元素来完成bean别名的定义。 如:<alias name="fromName" alias="toName"/>这里若是在容器中存 在名为fromName的bean定义,在增长别名定义以后,也能够用toName来引用。 考虑一个更为具体的例子,组件A在XML配置 文件中定义了一个名为componentA-dataSource的DataSource bean。 但组件B却想在其XML文件中以componentB-dataSource的名字来引用此bean。 并且在主程序MyApp的XML配置文件中,但愿以myApp-dataSource的名字来引用此bean。 最后容器加载三个XML文件来生成最终的ApplicationContext,在此情形下,可经过在MyApp XML文件中添加下列alias 元素来实现: <alias name="componentA-dataSource" alias="componentB-dataSource"/> <alias name="componentA-dataSource" alias="myApp-dataSource" /> 这样一来,每一个组件及主程序就可经过惟一名字来引用同一个数据源而互不干扰。 实例化bean就Spring IoC容器而言,bean定义基本上描述了建立一个或多个实际bean对象的内容。 当须要的时候,容器会从bean定义列表中取得一个指定的bean定义,并根据bean定义里面的配置元数据 使用反射机制来建立一个实际的对象。 所以这一节将讲解如何告知Spring IoC容器咱们将要实例化的对象的类型以及如何实例化对象。 当采用XML描述配置元数据时,将经过<bean/>元素的class属性来指定实例化对象的类型。class 属性 (对应 BeanDefinition实例的Class属性)一般是必须的(不过也有两种例外的情形)。 class属性主要有两种用途:在大多数状况下,容器将直接经过反射调用指定类的构造器来 建立bean(这有点等相似于在Java代码中使用new操做符); 在极少数状况下,容器将调用类的静态工厂方法来建立bean实例,class属性将用来指定实际具备静态工厂方法的类 (至于调用静态工厂方法建立的对象类型是当前class仍是其余的class则可有可无)。 用构造器来实例化当采用构造器来建立bean实例时,Spring对class并无特殊的要求,咱们一般使用的class都适用。 也就是说,被建立的类并不须要实现任何特定的接口,或以特定的方式编码,只要指定bean的class属性便可。 不过根据所采用的IoC类型,class可能须要一个默认的空构造器。 此外,IoC容器不只限于管理JavaBean,它能够管理任意的类。不过大多数使用Spring的人喜欢使用实际的JavaBean (具备默认的(无参)构造器及setter和getter方法),但在容器中使用非bean形式(non-bean style)的类也是能够的。 好比遗留系统中的链接池,很显然它与JavaBean规范不符,但Spring也能管理它。 当使用基于XML的元数据配置文件,能够这样来指定bean类: <bean id="exampleBean" class="examples.ExampleBean"/> <bean name="anotherExample" class="examples.ExampleBeanTwo"/> 给构造函数指定参数以及为bean实例设置属性将在随后的部份中谈及。 使用 静态工厂方法实例化当采用静态工厂方法建立bean时,除了须要指定class属性外, 还须要经过factory-method属性来指定建立bean实例的工厂方法。 Spring将调用此方法(其可选参数接下来介绍)返回实例对象,就此而言,跟经过普通构造器建立类实例没什么两样。 下面的bean定义展现了如何经过工厂方法来建立bean实例。注意,此定义并未指定返回对象的类型,仅指定该类包含的工厂方法。 在此例中, createInstance()必须是一个static方法。 <bean id="exampleBean" class="examples.ExampleBean2" factory-method="createInstance"/> 给工厂方法指定参数以及为bean实例设置属性将在随后的部份中谈及。 使用实例工厂方法实例化与使用静态工厂方法实例化相似,用来进行实例化的实例工厂方法位于另一个已有的bean中, 容器将调用该bean的工厂方法来建立一个新的bean实例为使用此机制,class属性必须为空,而factory-bean属性必须 指定为当前(或其祖先)容器中包含工厂方法的bean的名称,而该工厂bean的工厂方法自己必须经过factory-method属性 来设定(参看如下的例子)。 <!-- the factory bean, which contains a method called createInstance() --><bean id="myFactoryBean" class="..."> ... </bean> <!-- the bean to be created via the factory bean --><bean id="exampleBean" factory-bean="myFactoryBean" factory-method="createInstance"/> 虽然设置bean属性的机制仍然在这里被说起,但隐式的作法是由工厂 bean本身来管理以及经过依赖注入(DI)来进行配置。使用容器从本质上讲,BeanFactory仅仅只是一个维护bean定义以及 相互依赖关系的高级工厂接口。经过BeanFactory咱们能够访问bean定义。 下面的例子建立了一个bean工厂,此工厂将从xml文件中读取bean定义: InputStream is = new FileInputStream("beans.xml"); BeanFactory factory = new XmlBeanFactory(is); 基本上就这些了,接着使用getBean(String)方法就能够取得bean的实例; BeanFactory提供的方法极其简单。它仅提供了六种方法供客户代码调用: boolean containsBean(String): 若是BeanFactory包含给定名称的bean定义(或bean实例),则返回 trueObject getBean(String):返回以给定名字注册的bean实例。 根据bean的配置状况,若是为singleton模式将返回一个共享的实例,不然将返回一个新建的实例。 若是没有找到指定的bean,该方法可能会抛出BeansException异常(实际上将抛出NoSuchBeanDefinitionException异常), 在对bean进行实例化和预处理时也可能抛出异常Object getBean(String, Class): 返回以给定名称注册的bean实例,并转换为给定class类型的实例, 若是转换失败,相应的异常(BeanNotOfRequiredTypeException)将被抛出。 上面的getBean(String)方法也适用该规则。 Class getType(String name):返回给定名称的bean的Class。 若是没有找到指定的bean实例,则抛出NoSuchBeanDefinitionException异常。 boolean isSingleton(String):判断给定名称的bean定义 (或bean实例)是否为singleton模式(singleton将在bean的做用域中讨论),若是bean没找到,则 抛出NoSuchBeanDefinitionException异常。 String[] getAliases(String):返回给定bean名称的全部别名。