23JSP与Spring框架的应用.docx
《23JSP与Spring框架的应用.docx》由会员分享,可在线阅读,更多相关《23JSP与Spring框架的应用.docx(24页珍藏版)》请在冰点文库上搜索。
23JSP与Spring框架的应用
第23章JSP与Spring框架的应用
企业应用软件的开发变得越来越庞大,软件技术也越来越复杂。
Spring为已建立
的企业级应用提供了一个轻量级的解决方案,这个方案包括声明式事务管理,通过
RMI或webservices远程访问业务逻辑,mail支持工具以及数据库持久化的多种选择。
Spring还提供了一个MVC应用框架,可以透明的把AOP集成到软件中,另外还提供
了一个优秀的异常处理体系,包括自动从Spring特有的异常体系中映射。
本章我们将
要对Spring框架作简单介绍,并给出两个使用Spring的简单示例。
23.1Spring框架简介
Spring是一个开源框架,是为了解决企业应用程序开发复杂性而创建的。
该框架
的主要优势是其良好的设计和分层结构,软件开发人员可以只选择Spring提供的某项
技术,例如AOP,而不需要使用它提供的所有技术。
同时,Spring还提供了和其它开
源软件的无缝结合,为J2EE应用程序开发提供了集成的框架。
23.1.1Spring框架是什么
Spring是一个提供了解决J2EE问题的开源框架。
该框架的核心是控制反转,通
过配置文件来完成业务对象之间的依赖注入,它鼓励一个良好的习惯,那就是注入对
接口编程而不是对类编程。
Spring还提供了事务处理的功能,它能够在各种底层事务
处里技术上提供一个统一的编程模式。
Spring框架由7个模块组成,如图23-1所示。
SpringORMSpringWeb
SpringSpringWeb
AOPMVC
SpringDAOSpringContext
SpringCore
图23-1Spring框架结构图
下面我们来依次介绍每个模块:
(1)Core包:
该包是Spring框架的最基础部分,提供依赖注入(Dependency
Injection)特性来管理Bean容器功能。
这里用到的一个重要技术是BeanFactory,它提
供Factory模式来解决程序单例问题,并且允许编程人员从程序逻辑中分离出依赖关
系的配置和描述。
(2)Context包:
该包构建于Beans包的基础之上,提供了一种框架式的Bean
访问方式,类似于JNDI注册。
(3)DAO包:
该包提供了JDBC的抽象层,它封装了冗长的JDBC编码和解析
数据库厂商特有的错误代码。
另外它还提供了一种方法实现编程性和声明性事务管理,
不仅仅是针对实现特定接口的类,而是对所有的POJO。
(4)ORM包:
该包为流行的“关系-对象”映射API提供了集成层,包括JDO、
Hibernate和iBatis。
通过ORM包,编程人员可与所有Spring提供的其他特性相结合
来使用这些“对象—关系”映射,如前边提到的简单声明性事务管理。
(5)AOP包:
该包提供了面向方面编程的功能,由于Spring的核心是基于控制
反转的,所以可以用Spring的依赖注入为AOP提供支持。
(6)Web包:
该包提供了基本的面向Web的综合特性,如Multipart功能,使用
Servlet监听器的Context的初始化和面向Web的ApplicatinContext。
当Spring与
WebWork或Struts一起使用时,这个包使Spring可与其它框架结合。
(7)WebMVC包:
该包提供了面向Web应用的Model-View-Controller实现。
Spring的MVC实现不仅仅是一种实现,它不仅提供了一种domainmodel代码和web
form的清晰分离,还可以使用Spring框架的所有其他特性,如校验。
23.1.2为什么要用Spring框架
Spring框架之所以能迅速地在Java开发人员中流行,是因为它具有以下特点:
(1)设计良好的分层结构,使得开发人员可以简单的进行扩充,并引入先进的设
计理念。
(2)以IoC为核心,促使开发人员面向接口编程,可以养成良好的编程习惯,从
而便于程序的扩充和维护。
(3)良好的架构设计,使得应用程序尽可能少地依赖应用程序的环境,从而使得
应用脱离了环境的影响。
(4)Spring能够替代EJB。
如果开发人员原来使用EJB,则使用Spring后还可以
继续使用EJB,如果要从头开发应用程序,则开发人员可以完全脱离EJB,而只使用
Spring提供的功能就可以替代EJB。
(5)SpringMVC很好的实现了MVC2,并提供了很简单的对国际化与资源访问
的支持,而且可以和Spring提供的IoC和AOP联系起来。
(6)Spring可以与其它框架良好的结合,例如与Struts、Hibernate等结合,使得
应用开发更为容易。
23.2Spring安装与配置
在介绍Spring的使用之前,我们先来做一些准备工作,即完成工作环境的搭建,
包括Spring的下载,安装和配置。
下面我们就来分别介绍这些工作。
23.2.1下载Spring
从http:
//www.springframework.org下载Spring。
下载页面如图23-2所示。
下载
spring-framework-2.5-with-dependencies.zip到本地硬盘。
图23-2Spring下载页面
下载页面可以看到spring-framework-2.5-with-dependencies.zip和
spring-framework-2.5.zip两个版本,建议读者下载前者,因为前者比后者多了一些
Spring要用到的第三方包,如hibernate、j2ee、dom4j、aopalliance、jakarta-commons
等。
下载包名称的dependencies就是“依赖”的意思。
23.2.2安装Spring
将下载的文件解压后,可以得到如下目录:
zdist:
Spring的核心库。
zdocs:
Spring的一些相关文档。
zlib:
一些可能用到的第三方库。
zsamples:
Spring项目示例。
zsrc:
Spring的源代码。
ztest:
测试用例。
Spring的安装非常简单,与JSF类似,只要将用到的JAR包放到Web应用的组件
库中即可。
这里我们先在Eclipse中建立一个TomcatProject,这一步前面已经多次讲
过,这里不再赘述。
然后将需要的JAR包放到WEB-INF/lib目录下即可。
如果我们只
是编写一个比较简单的应用程序,只要spring-core.jar包就可以了,如果还要用到Spring
的其它技术,例如AOP,这时就要把spring-aop.jar包也放进来。
不过还有一个更简单
的方法,那就是使用spring.jar包,它包括了Spring需要的所有JAR包,这样就不用
考虑会用到那种技术了,一个包就解决了。
在此,建议大家都使用spring.jar包。
注意,还有一个细节,使用Spring时,Spring本身的组件会用到日志元件,所以
还要把spring-framework-2.5/lib/jakarta-commons目录下的“commons-logging.jar”放
到应用程序的/WEB-INF/lib目录下。
23.2.3配置Spring
在Eclipse中使用Spring框架就要先对其进行配置,即引用Spring库文件,如图
23-3所示,单击“AddJARs…”,选择lib目录下的JAR包即可。
图23-3配置Spring
23.3控制反转/依赖注入机制
Spring的核心思想是控制反转(即IoC),另一个与它关系非常密切的概念是依赖
注入(即IntefaceInjection),通常人们认为两者是等价的,其实它们之间有细微的区
别。
本小节我们将为大家详细讲述IoC/DI的思想。
23.3.1控制反转/依赖注入简介
IoC的全称是InversionofControl(控制反转),它是Spring的核心思想。
直观地
讲,就是由容器控制程序之间的关系,而不是传统模式中,由程序代码直接控制。
控
制权由应用代码中转到了外部容器,控制权的转移是所谓反转。
这也是这个名字的来
历。
控制反转的实现策略有两种:
z依赖查找:
容器中的受控对象通过容器的API来查找自己所依赖的资源和协
作对象。
这种方式虽然降低了对象间的依赖,但是同时也使用到了容器的
API,造成了无法在容器外使用和测试对象。
z依赖注入:
对象只提供普通的方法让容器去决定依赖关系,容器全权负责组
件的装配,它会把符合依赖关系的对象通过属性(JavaBean中的getter和
setter,.NET中的property)或者是构造函数传递给需要的对象。
第二种策略让容器去全权负责依赖查询,受控对象只要暴露属性和代参数的构造
函数,使容器可以在初始化对象的时候设置对象间的依赖关系。
这种方式往往不需要
依赖特定API和接口,完全只要依赖语言本身就可以实现了。
所以,在大多数情况下,人们把控制反转和依赖注入看作同一个概念,其实依赖
注入是控制反转思想的一种实现策略。
依赖注入有三种实现方式,下一节将为大家作
详细介绍。
23.3.2依赖注入的三种实现方式
依赖注入有三种实现方式,它们分别是:
zSet注入(setterinjection):
通过JavaBean的属性(例如setter方法)分配依
赖性。
z构造注入(constructorinjection):
依赖性以构造函数的形式提供,即用构造
函数的参数提供注入的信息。
z接口注入(interfaceinjection):
定义专门的接口,通过实现这些接口,由对
象提供信息注入。
下面我们用两个示例来为分别大家演示如何使用这三种注入方式。
(1)Set注入
我们用一个简单的“Hello,spring!
”示例来演示如何使用Set注入方式,该应用程
序用到两个java文件和一个配置文件,下面我们给出具体代码。
①HelloSpring.java文件:
这是一个简单的JavaBean,包括一个字符串(欢迎信
息)和一个setter、一个getter,代码如下:
packagehellospri;
publicclassHelloSpring{
publicStringwelcome=null;
publicvoidsetWelcome(Stringwel){
welcome=wel;
}
publicStringgetWelcome(){
returnwelcome;
}
}
②HelloSpringTest.java文件:
由于这个小程序非常简单,我们没有作JSP页面,
所以只用一个java程序来测试我们在配置文件(稍后将会讲解)中配置的信息是否成
功注入到上面我们所讲的JavaBean中了,测试文件的代码如下:
packagehellospri;
importorg.springframework.context.ApplicationContext;
importorg.springframework.context.support.FileSystemXmlApplicationContext;
publicclassHelloSpringTest{
publicstaticvoidmain(String[]args){
ApplicationContextctx=newFileSystemXmlApplicationContext("config-hello.xml");
HelloSpringhp=(HelloSpring)ctx.getBean("HelloSpring");
System.out.println(hp.getWelcome());
}
}
可以看出,程序首先利用ApplicationContext获取配置文件,然后根据配置文件的
信息构造出一个JavaBean对象,当然配置文件中的信息同时也就注入到了该bean中,
最后,通过该对象的getter获取该信息,展示给用户。
③配置文件:
Spring的配置文件作用很大,可以通过它构建程序中使用的bean,
而不用显式的建立,使用时只要通过Spring提供的接口方法查找即可。
下面我们给出
该示例中所使用到的配置文件的内容:
xmlversion="1.0"encoding="UTF-8"?
>
DOCTYPEbeansPUBLIC"-//SPRING//DTDBEAN//EN"
"http:
//www.springframework.org/dtd/spring-beans.dtd">
Hello,Spring!
其中:
zid:
用来唯一标识该bean。
zclass:
用来标识该bean对应的类文件。
zname:
该bean的属性名。
zvalue:
为该属性注入的值。
该配置文件命名为“config-hello.xml”,保存在当前应用的根目录下,即/spri目录
下。
上面工作完成后,我们来运行测试程序“HelloSpringTest”,结果如图23-4所示:
图23-4HelloSpring示例运行结果
(2)构造注入
下面我们来对“Hello,spring!
”进行改写,让它使用构造注入方式,首先在
HelloSpring.java文件中加入构造器代码:
publicHelloSpring(Stringwe){
welcome=we;
}
然后改写配置文件,代码如下:
xmlversion="1.0"encoding="UTF-8"?
>
DOCTYPEbeansPUBLIC"-//SPRING//DTDBEAN//EN"
"http:
//www.springframework.org/dtd/spring-beans.dtd">
Hello,Sprng(constructor)!
其中constructor-args用来表示是通过构造方式来注入参数的。
运行结果如图23-5所示:
图23-5HelloSpring的构造注入方式
(3)接口注入
下面我们用另外一个稍微复杂一点的示例为大家演示接口注入方式,该示例是一
个使用Spring与MySQL数据库建立连接的示例,该示例中我们依然使用第22章我们
建立的数据库及其数据,然后使用Spring提供的IoC思想,利用接口注入的实现技术
从数据库中读取数据。
首先编写用来获取数据的接口DataBase,该接口只有一个方法getData()。
DataBase.java的代码如下:
packagemysqlspri;
publicinterfaceDataBase{
publicvoidgetData();
}
然后,我们编写针对具体数据库的MysqlDataBase类实现DataBase接口,该类只
有一个方法getData(),在该方法中实现了与数据库建立连接、查询数据并显示结果的
功能,代码如下:
packagemysqlspri;
importjava.io.UnsupportedEncodingException;
importjava.sql.Connection;
importjava.sql.Date;
importjava.sql.DriverManager;
importjava.sql.ResultSet;
importjava.sql.SQLException;
importjava.sql.Statement;
publicclassMysqlDataBaseimplementsDataBase{
publicvoidgetData(){
Stringurl="jdbc:
mysql:
//localhost/dbtest";
Stringusername="root";
Stringpwd=null;
Connectionconn=null;
Stringsql=null;
Statementstmt=null;
try{
Class.forName("com.mysql.jdbc.Driver");
}catch(ClassNotFoundExceptione){
System.out.println("加载驱动器类出现异常");
}
try{
conn=DriverManager.getConnection(url,username,pwd);
stmt=conn.createStatement();
sql="select*fromstudent";
ResultSetrs=stmt.executeQuery(sql);
while(rs.next()){
Stringstudentid=rs.getString
(1);
Stringname=newString(rs.getString
(2).getBytes("ISO-8859-1"),"gbk");
Stringaddress=newString(rs.getString(3).getBytes("ISO-8859-1"),"gbk");
Datebirthday=rs.getDate(4);
System.out.println(studentid+","+name+","+address+","+birthday);
}
rs.close();
stmt.close();
}catch(SQLExceptione){
System.out.println("连接出现异常");
}catch(UnsupportedEncodingExceptione){
e.printStackTrace();
}finally{
if(conn!
=null){
try{
conn.close();
}catch(SQLExceptione){
System.out.println("关闭连接出现异常");
}
}
}
}
}
注意,这里我们用到了MySQL数据库的驱动,所以要将“mysql-connector
-java-5.1.5-bin.jar”包放到该应用的/WEB-INF/lib目录下。
下面我们来编写使用DataBase接口获取数据库数据的业务逻辑,该类不会随数据
库的改变而改变,它只与DataBase接口打交道,DataBaseBusiness.java的代码如下:
packagemysqlspri;
publicclassDataBaseBusiness{
privateDataBasedb;
publicvoidsetDataBase(DataBased){
db=d;
}
publicvoidgetData(){
db.getData();
}
}
最后,我们来编写测试类MysqlDataBaseTest.java,在这个类中,我们用到了具体
的数据库MysqlDataBase,并用它对接口DataBase做接口注入,然后调用接口的
getData()方法获取数据库的数据,代码如下:
packagemysqlspri;
publicclassMysqlDataBaseTest{
publicstaticvoidmain(String[]args){
DataBaseBusinessbs=newDataBaseBusiness();
bs.setDataBase(newMysqlDataBase());
bs.getData();
}
}
运行结果如图23-6所示:
图23-6Spring与MySQL数据库连接
我们可以直接用mysql命令查询数据库中数据,结果如图23-7所示:
图23-7直接查询数据库
对比两个图可以看到结果是正确的。
通过这个示例我们体会到了使用IoC的好处,当我们要改用别的类型数据库时,
只要编写一个实现DataBase接口的类就可以了,其他代码都不用修改,降低了编码复
杂性,同时提高了程序的可维护性。
在实际使用中,选用哪种注入方式要根据具体情况来决定:
使用Set注入可以有
明确的名称,可以了解注入的属性是哪个,像setXXX()这样的名称比起记忆Constructor
上每个参数位置代表什么更容易。
但是,由于Set注入提供了setXXX()方法,就不能
保证相关的数据成员在执行时不会被动态修改,所以如果开发人员想要让一些数据成
员变为只读或私有,最好使用构造注入的方式。
23.4AOP思想
AOP的全称是AspectOrientedProgramming,即面向方面编程,它是Spring中一
个非常重要的思想。
本小节我们就来对AOP做简单的讲解。
23.4.1AOP思想简介
AOP思想的出现其实是为了实现一个目的——代码的“解耦”。
它其实是一种分
散关注的思想:
将通用需求功能从不相关类之中分离出来;同时,能够使得很多类共
享一个行为,一旦行为发生变化,不必修改很多类,只要修改这个行为就可以。
AOP就是这种实现分散关注的编程方法,它将“关注”封装在“方面”中。
这种说法也许太抽象了,下面我们用一个例子来说明。
假设在一个应用系统中,
有一个共享的数据必须被并发同时访问,首先,将这个数据封装在数据对象中,称为
DataClass;同时,将有多个访问类,专门用于在同一时刻访问这同一个数据对象。
为了完成上述并发访问同一资源的功能,需要引入锁Lock的概念,也就是说,
某个时刻,当有一个访问类访问这个数据对象时,这个数据对象必须上锁Locked,用
完后就立即解锁unLocked,再供其它访问类访问。
使用传统的面向对象编程思想,我们会创建一个抽象类,所有的访问类继承这个
抽象父类,代码如下:
abstractcl