大名鼎鼎的Spring 大家都听过, spring 是一个开源框架, Spring 为简化企业级应用开发而生。使用 Spring 可以使简单的 JavaBean 实现以前只有 EJB 才能实现的功能。 Spring 是一个 DI (依赖注入)和 AOP (面向切面编程)容器框架。
Spring具体应用细节,以及与 struts 和 hibernater 的整合。我们还没有学习到,今天算是 Spring 的基础操作和实现 IOC (控制反转)以及 DI (依赖注入)的原理。
一、spring 框架
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。 Spring 模块构建在核心容器之上,核心容器定义了 创建、配置和管理 bean 的 方式,如图 1 所示。
Spring框架概述
组成 Spring 框架的每个模块(或组件)都可以单独存 在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
· 核心容器 : 核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory ,它是工厂模式的实现。 BeanFactory 使用控制反转 ( IOC ) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
· Spring 上下文 : Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。 Spring 上下文包括企业服务,例如 JNDI 、 EJB 、电子邮件、国际化、校验和调度功能。
· Spring AOP : 通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集 成到了 Spring 框架 中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP 。 Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP ,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
· Spring DAO : JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且 极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。 Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
· Spring ORM : Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO 、 Hibernate 和 iBatis SQL Map 。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
· Spring Web 模 块 : Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以, Spring 框架支持与 Jakarta Struts 的集成。 Web 模块还简化了处理多部分请求以及将请求参数绑 定到域对象的工作。
· Spring MVC 框架 : MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口, MVC 框架变成为高度可配置的, MVC 容纳了大量视图技术,其中包括 JSP 、 Velocity 、 Tiles 、 iText 和 POI 。
Spring 框架的功能可以用在任何 J2EE 服务器中,大多数功能也适用于不受管理的环境。 Spring 的核心要点是:支持不绑定到特定 J2EE 服务的可重用业务和数据访问对象。毫无疑问,这样的对象可以在不同 J2EE 环境 ( Web 或 EJB )、独立应用程序、测试环境之间重用。
我们今天的重点内容是—— 核心容器。
二、HelloSpring
这个“HelloWorld! ”的经典程序,还要引领多长时 间?可能会一直下去吧。我们现在就开始编写一个 Spring 的 HelloWorld! 程序,来学习一下 Spring 环境的搭建。
1. 安装Spring 的 Eclipse 插件。
2. 新建立一个Java 工程,在工 程上右键 ->Spring Tools->Add Spring Project Nature 。
3. 导入“spring-framework-2.5.6.SEC01\dist\spring.jar ”和“ spring-framework-2.5.6.SEC01\lib\jakarta-commons\commons-logging.jar ”。我们使用的 Spring 的版本是 2.5 , 3.0 刚 刚出来。但 3.0 与 2.5 的区别不是很大。
4. 在工程中添加“HelloSpring.java ”:
package cn.itcast.cc.spring; public class HelloSpring { private String message ; // 构造函数 public HelloSpring() { System. out .println( "HelloSpring,Construct!" ); } // Spring通过此方法注入属性值 public void setMessage(String message) { this . message = message; } // 打印消息 public void hello() { System. out .println( "Hello:" + this . message ); } }
5. 在“src ”目录下,新建一个“ applicationContext.xml ”文件。(在“ src ”目录上右键 ->New->Other->Spring->Spring Bean Definition ):
<? 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.xsd" > <!-- 描述一个Bean,name指定Bean的名称,class指定Bean类名 --> < bean name = "helloSpring" class = "cn.itcast.cc.spring.HelloSpring" > <!-- property设置属性值,name指定名称,value指定属性值 --> < property name = "message" value = "**Spring**" /> </ bean > </ beans >
6. 添加测试类:
package cn.itcast.cc.spring; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { public static void main(String[] args) { // 创建应用程序环境 ApplicationContext appCon = new ClassPathXmlApplicationContext( "applicationContext.xml" ); // 获取名称为helloSpring的Bean HelloSpring hs = (HelloSpring) appCon.getBean( "helloSpring" ); // 调用Bean的方法 hs.hello(); } }
7. 控制台输出:
指定Bean 的名称,可以使用 name ,也可以使用 id 。一般情况下建议使用 id ,因为 id 在 XML 文件中是一个特殊的属性, XML 会自动校验 ID 的唯一性。
可能通过属性的setter 方法或着 Bean 的构造函数设置属性的值,但 setter 是比较常用的。使用构造函数设置属性的 值,使用“ < constructor-arg value = "**Spring**" /> ”替换“ property ”元素。注意一定要有与之对应的构造方法。
从刚开始的Dao 接口到工厂模式再到 Spring 框架,都是为了实现更好的解耦。
三、Spring 的配置文件
1.引用 Bean
在应用中经常会遇见一个Bean 实体,将另一个 Bean 实体做为自己的属性。那么这个属性值我们在 XML 文件中应该如何指定呢? Property 有一个 ref 属性, ref 属性的值设置为指定 Bean 元素的名称即可。
2.内部 Bean
当一个Bean 实体只被用作另一个 Bean 的属性时。我们可以将这个 Bean 声明为内部 Bean 。内部 Bean 无须设置它的 id 或 name 值,它被做为子元素嵌入在对应 property 元素中。
3.继承式 Bean
bean元素中“ depends-on ”属性用来指定父类。
Spring 允许将通用的 Bean 配置抽象出来, 组成一个父 Bean 。 继承这个父 Bean 的 Bean 称为子 Bean 。
子 Bean 从父 Bean 中继承配置, 包括 Bean 的属性和在 <bean> 元素里的属性。
子 Bean 也可以覆盖从父 Bean 继承过来的配置。
父 Bean 可以作为配置模板, 也可以作为 Bean 实例。 若只想把父 Bean 作为模板, 可以设置 <bean> 的 abstract 属性为 true , 这样 Spring 将不会实例化这个 Bean 。
并不是 <bean> 元素里的所有属性都会被继 承。 比如: autowire , dependency-check , abstract 等。
也可以忽略父 Bean 的 class 属性, 让子 Bean 指定自己的类, 而共享相同的属性配置。 但此时 abstract 必须设为 true 。
4.设置集合属性
经常见到Bean 具有集合属性,在 hibernate 的 XML 文件中也可以设置集合属性的值。
在 Spring 中可以通过一组内置的 xml 标签 ( 例如: <list> , <set> 或 <map>) 来配置集合属性。
需求: 序列号生成器需要使用多个后缀。 这些后缀使用 “- ” 作为分割, 附加在序列号后边。 这些后缀可以是任意的数据类型, 在拼接时将它们转换为字符串。
也可以使用“utility scheme ”工具,定义可重用的集合 设置,引时 xml 文件需要引 入特定的标签库,参照下面的内容。
5.检查属性
设置Bean 的“ dependency-check = "objects" ”属性,检查bean 中的所有属性是否通过 setter 方法注入了值。如果是通过构造方法注入,或没有注入都会抛异常。 Dependency-check 不检查属性值是否合法。
在bean 中设置“ dependency-check = "objects" ”属性,它会检查所有属性。如果我们想要检查某一个属性怎么办?首先添加一个:
HelloSpring,Construct! Hello:**Spring** |
或
使用“ < context:annotation-config /> ”时,beans 的元素属性内容为:
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" /> <context:annotation-config /> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd "> |
然后在Bean 的 setter 方法上添加“ @Required ”注解,这样 Spring 将检查被标“ @Required ”注解的属性。
如果使用的是JRE1.5 需要添加“ spring-framework-2.5.6.SEC01\lib\j2ee\common-annotations.jar ” jar 。
6.Bean 自动装配
Spring IOC 容器可以帮助自动装配 Bean 。需要做的仅仅是在 <bean> 的 autowire 属性里指定自动装配的模式。
byType(根据类型自动 装配 ) : 若 IOC 容器中有多个与目标 Bean 类型一致的 Bean 。在这种情况下, Spring 将无法判定哪个 Bean 最合适该属性,所以不能执行自动装配。
byName(根据名称自动装配 ) : 必须将目标 Bean 的名称和属性名设置的完全相同。
constructor(通 过构造器自动装配 ) : 当 Bean 中存在多个构造器时, 此种自动装配方式将会很复杂。 不推荐使用。
四、Spring 的注解
通过Xml 文件配置应用程序是之前流行的方式,但不够直观和 便利。现在流行使用注解了。在 Spring2.5 (包括 2.5 )之后就开始支持注解了。
使用注解时,我们只需要将Spring 的配置文件内容设置为:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd "> <context:annotation-config /> </beans>
|
“ @Component ”: 基本注解, 标识了一个受 Spring 管理的组件。
“ @Respository ”: 标识持久层组件。
“ @Service ”: 标识服务层(业务层)组件。
“ @Controller ”: 标识表现层组件。
“ @Autowired ”自动装配具有兼容类型的单个 Bean 属性。默认情况下, 所有使用 @Authwired 注解的属性都需要被设置。 当 Spring 找不到匹配 的 Bean 装配属性时, 会抛出异常, 若某一属性允许不被设置, 可以设置 @Authwired 注解的 required 属性为 false 。
构造器, 普通字段( 即使是非 public) , 一切具有参数的方法都可以应用 @Authwired 注解。
它可以应用在数组类型的属性上, 此时 Spring 将会把所有匹配的 Bean 进行自动装配。
它可以应用在集合属性上, 此时 Spring 读取该集合的类型信 息, 然后自动装配所有与之兼容的 Bean 。
它用在 java 、 util 、 Map 上 时, 若该 Map 的键值 为 String , 那么 Spring 将自动装配与之 Map 值类型兼容的 Bean , 此时 Bean 的名称作为键值。
默认情况下, 当 IOC 容器里存在多个类型兼容的 Bean 时, 通过类型的自动装配将无法工作。 此时可以在 @Qualifier 注解里提供 Bean 的名称。但该注解只能用于修饰字段, 不能用于修饰方法
“ @Resource ”通过名称自动装配 Bean 属性,若没有名称一致的装配类型一致的。
构造器, 普通字段( 即使是非 public) , 一切具有参数的方法都可以应用 @ Resource 注解。
默认情况下,Spring 将试着找出和属性名称相同的 Bean 。也可以在 @Resource 注解的 name 属性里指定 Bean 的名称。
五、Spring 高级特性
1.Bean的作用域
如果不为指定Bean 的作用域, Spring 默认( scope="singleton" )只维护一个 Bean 实例,所有调用同一 getBean(name) 的位置都返回同一实例。设 置 Bean 的作用域为“ scope="property" ” Spring 都返回一个对应 Bean 的新的实例。
2.Bean的初始化和销毁过程
在企业开发中,组件在使用之前往往需要执行一些特定类型的初始 化任务,其中包括打开文件,打开网络/ 数据 库连接,分配内存等。同样,当组件结束其生命周期时,也需要执行与之对应的销毁任务。
设置Bean 的初始化和销毁过程。“ @PostConstruct ”调用Bean 的初始化过程,当 Bean 创建后并设置属性值后会调标注了此注解的方法。“ @PreDestroy ”调用Bean 的销毁过程,当 Bean 被销前会调用标注了此注解的方法。
注意:当Spring 只维护一个 Bean 实例时, Bean 被销前会调用标注了“ @PreDestroy ”注解的方法,否则不会调用。
3.Bean 后置处理器
Bean后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理。
Bean后置处理器对 IOC 容器里的所有 Bean 实例逐一处理,而非单一实例。其典型应用是:检 查 Bean 属性的正确性或根 据特定的标准更改 Bean 的 属性。
对Bean 后置处理器而言,需要实现接口“ BeanPostProcessor ”。在初始化方法被调用前后,Spring 将把每个 Bean 实例分别传递给上述接口的以下两个方法:
“ postProcessAfterInitialization ”和 “ postProcessBeforeInitialization ”。
SpringIOC容器对 Bean 的生命周期进行管理的过程:
1).通过构造器或工厂方法 创建 Bean 实例
2).为 Bean 的属性设置值和对其他 Bean 的引用
3).将 Bean 实例传递给 Bean 后置处理器的 postProcessBeforeInitialization 方法
4).调用 Bean 的初始化方法
5).将 Bean 实例传递给 Bean 后置处理器的 postProcessAfterInitialization 方法
6).Bean可以使用了
7).当容器关闭时,调用 Bean 的销毁方法
注册Bean 后置处理器,只需要在配置文件里声明声明一个该 处理器的实例, ApplicationContext 会探测到实现了 BeanPostProcessor 接口的 Bean 并进行注册。
若初始化和销毁方法是通过添加生命周期注解@PostConstructor 和 @PreDestory 实现的,则自定义的 Bean 后置处理器将无法工作。其原因是 CommonAnnotationBeanPostProcessor 的优先级比自定义的 Bean 后置处理器的优先级高。结果在对路径检查之前初始化方法已经被调用。
要定义Bean 后置处理器的处理顺序,需要让 Bean 后置处理器的实例实现 Ordered 或者 PriorityOrdered 接口,在 getOrder() 方法中返回顺序值。该方法返回的 数值越低优先级越高。另: PriorityOrdered 接口返回的顺序值总优先于 Ordered 接口返回的顺序值,而 CommonAnnotationBeanPostProcessor 实现了 PriorityOrdered 接口。
4.外部化 Bean 的配置
在配置文件里配置Bean 时,有时需要在 Bean 的配置里混入系统部署的细节信息 ( 例如:文件路径,数据源配置信息等 ) 。而这些部署细节实际上需要和 Bean 配置相分离。
Spring提供了一个 PropertyPlaceholderConfigurer 的 BeanFactory 后置处理器,这个处理器允许用户将 Bean 配置的部分内容外移到属性文件中。可以在 Bean 配置文件里使用形式为 ${var} 的变量, PropertyPlaceholderConfigurer 从属性文件里加载属性,并使用这些属性来替换变量。
在Spring2.0 中注册 PropertyPlaceholderConfigurer :
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="c3p0.properties" /> </bean>
|
在Spring2.5 中可通过 <context:property-placeholder> ,简化注册 PropertyPlaceholderConfigurer :
<context:property-placeholder location="classpath:c3p0.properties"/> |
此时beans 的属性内容为:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd ">