《Java EE主流开源框架》第2部分 Spring框架_第1页
《Java EE主流开源框架》第2部分 Spring框架_第2页
《Java EE主流开源框架》第2部分 Spring框架_第3页
《Java EE主流开源框架》第2部分 Spring框架_第4页
《Java EE主流开源框架》第2部分 Spring框架_第5页
已阅读5页,还剩235页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Java主流开源框架Spring框架——导读Spring框架是主流的JavaWeb开发框架,是一个轻量级的开源框架,具有很高的凝聚力和吸引力,在企业应用开发中被广泛使用。Spring框架由RodJohnson创立,在2004年发布了Spring框架的1.0正式版,其目的是用于降低企业应用程序开发的难度和缩短开发周期。Spring框架不局限于服务器端的开发。从简单性、可测试性和松耦合的角度看,任何Java应用都可以从Spring框架中受益。Spring框架还是一个超级黏合平台,除自己提供功能外,还具有黏合其他技术和框架的能力。本部分详细介绍了Spring框架的多个知识点内容,主要包括依赖注入DI、控制反转IoC、面向切面编程AOP、

XML配置实现、注解实现,以及Spring框架对Web层、数据访问层的支持等内容。并通过丰富的案例帮助读者加深理解。通过学习,读者可以更好地知道Spring框架是什么、有什么优点、怎么用等。2.1

Spring框架概述:Spring框架的创始人是Rod

Johnson,他曾是一位Java

EE技术专家,他在工作中发现Java

EE系统组件的一些弊端会使系统过于臃肿,于是出版了Expert

One-on-One™,J2EE

Design

and

Development(中文版译名为《J2EE设计开发编程指南》)。他在该书中分析了Java

EE业务组件EJB(2.0版本)的种种弊端,提出了基于实用主义的业务层框架,并将其开源后在互联网上发表,这就是后来的Spring框架。Spring框架可以被看成一个标准的开发组件,是一个轻量级的非入侵式框架,使用Spring框架开发的业务对象不需要依赖

Spring框架的API。可以把Spring框架看成一个容器,它能够管理业务对象的生命周期,是可以整合各种企业应用的开源框架和优秀的第三方类库。读者可以在Spring官方网站下载完整的类库、源代码及文档,本书基于Spring

4.2版本组织学习内容。第21章SJparvianEgE框W架eb快开速发入概门述2.2

Spring框架的体系结构:如图2-1所示,Spring框架的模块被划分为五个层,每个层次解决不同的问题,下面对这五个层次进行简单的介绍。1.Core

Container层Core

Container层(核心容器层)包括Beans模块、Core模块、Context模块、SpEL模块。Beans模块和Core模块是Spring框架的基础部分,提供IoC(控制反转)和DI(依赖注入)功能,将在后续章节中详细介绍。Context模块构建在Beans模块和Core模块的基础上,提供类似于JNDI注册器的框架式对象访问方法;同时,Context模

块也支持Java

EE的一些特性,例如EJB、JMX和基础的远程处理等。ApplicationContext接口是Context模块的核心接口。SpEL模块提供一种强大的表达式语言,用于在运行时查询和操纵对象。第21章SJparvianEgE框W架eb快开速发入概门述2.1

Spring框架概述:2.AOP及Instrumentation层AOP及Instrumentation层包括AOP模块、Aspects模块、Instrumentation模块、Messaging模块。AOP(面向切面编程)模块提供一个符合AOP联盟标准的面向切面编程的实现,是Spring框架除IoC外的另一个核心技术,将在后续章节中详细介绍。Aspects模块提供对AspectJ的集成支持。Instrumentation模块提供Class

Instrumentation支持及Classloader实现,可以在特定的应用服务器上使用框架。Messaging模块为集成消息API和消息协议提供支持。第21章SJparvianEgE框W架eb快开速发入概门述2.1

Spring框架概述:3.Web层Web层包括WebSocket模块、Servlet模块、Web模块、Portlet模块。WebSocket模块提供浏览器与服务端建立通信方式的支持。Servlet模块包含Spring的MVC实现,本书将详细介绍Spring

MVC的使用。Web模块提供基础的面向Web的集成特性,例如多文件上传、使用Servlet监听器初始化IoC容器及面向Web的应用上下文等,还包含Spring远程支持中的Web相关的功能。Portlet模块提供用于Portlet环境和WebServlet模块的MVC的实现。第21章SJparvianEgE框W架eb快开速发入概门述2.1

Spring框架概述:4.Data

Access/Integration层(数据访问/集成层)Data

Access/Integration层(数据访问/集成层)包括JDBC模块、ORM模块、OXM模块、JMS模块、Transactions模块。JDBC模块提供JDBC抽象层,简化访问数据库的方式。ORM模块为流行的ORM框架(例如JPA、JDO、Hibernate、MyBatis等)提供交互层,可以便捷地集成各种数据访问层框架,本书将着重介绍MyBatis框架。OXM模块提供一个Object/XML映射实现的抽象层。JMS(Java

Messaging

Service)模块主要包含制造和消费消息的特性。Transaction(事务)模块支持编程和声明性的事务处理。5.Test层Test层(测试层)支持在JUnit和TestNG下对Spring组件进行单元测试与集成测试。第21章SJparvianEgE框W架eb快开速发入概门述2.3核心概念—IoC:IoC(Inversion

of

Control)称为控制反转,是Spring框架的核心基础,可以说Spring框架的一切功能都是基于IoC而来的,将在后续章节中详细介绍,本节简单介绍概念。在解释什么是IoC之前,先从一个例子开始。任何一个应用都是若干个对象互相协作完成的。创建一个对象后,总是需要对这个对象所依赖的属性进行初始化。代码如下所示:第21章SJparvianEgE框W架eb快开速发入概门述public

class

A{private

B

b;public

void

setB(B

b){

this.b=b;}}public

class

B{private

C

c;public

void

setC(C

c){

this.c=c;}}public

class

C{}上述代码中共有三个类,分别是A类、B类和C类。其中,A类实例总是依赖一个B类实例,而B类实例总是依赖一个C类实例。因此,想正常使用A类实例,需要如下所示的创建装配的过程:C

c=new

C();B

b=new

B();b.setC(c);A

a=new

A();a.setB(b);2.3核心概念—IoC:上篇代码中通过创建C类实例,把C类实例注入给B类实例,再将B类实例注入给A类实例,最终构建出一个可用的A类实例。在实际应用中,类似这样的代码随处可见,A类实例越复杂,则对其装配的过程越复杂。如果装配关系有所变化,则需要修改源代码。如果使用Spring框架构建应用,则对实例之间的装配关系不再需要自行编写代码控制,可以交给IoC容器来实现,容器通过解析XML配置文件或者注解即可正确装配,这就是所谓的“控制反转”,即控制权由应用代码中转到了外部容器,控制权

的转移就是反转。从另外的角度出发,IoC也被称为DI(Dependency

Injection,依赖注入)。依赖注入非常直观地描述了这一特征,即应用程序依赖IoC容器注入需要的实例等资源。可以说,IoC和DI是本质相同的概念,区别是角度不同,IoC从容器的角度出发,而DI从应用程序的角度出发。第21章SJparvianEgE框W架eb快开速发入概门述2.4核心概念—AOP:在企业应用中,很多模块可能需要实现相同的功能,如多个模块都需要日志功能、权限校验功能、事务处理功能等,这些相同的功能就被称为“切面”。AOP(Aspect

Oriented

Program,面向切面编程)能够将通用的功能与业务模块分离,是OOP(Object

OrientedProgram,面向对象编程)的延续和补充。AOP并不是Spring框架提出的技术,早在1997年就由Gregor

Kiczales领导的

研究小组提出。目前,已有上百种项目宣称能支持AOP,Spring框架是众多支持AOP项目中的一个。例如,在一个应用中有用户管理、订单管理、支付等功能模块,每个模块都需要记录日志,那么就可以把日志看作一个切面单独进行开发,然后使用Spring框架的AOP支持编程,能降减少码冗余,提高工作效率。同时,如果日志功能需要改变,不需要修改其他功能模块的源代码,只要单独更新日志相关代码即可,大大提高了程序的可扩展性。第21章SJparvianEgE框W架eb快开速发入概门述2.4核心概念—AOP:单独开发日志功能后,可以使用AOP编程将日志功能“织入”各个功能模块中,“织入”的过程不需要修改功能模块的源代码,只通过XML配置文件或注解即可完成。第21章SJparvianEgE框W架eb快开速发入概门述3.1

BeanFactory与ApplicationContext:上一章提到,IoC是Spring框架的核心技术,也是框架所有功能的基础。Spring框架实现了IoC容器,能够根据配置文件或注解为应用程序生成对象,并管理这些对象的生命周期,这些对象被称为bean。容器生成bean后,应用程序需要能够访问这些bean进而实现应用功能。Spring

IoC容器的代表是API中的BeanFactory接口。IoC容器装配成功的bean都可以通过BeanFactory获得,进而在应用中使用。BeanFactory中提供的getBean方法可以获得bean对象,如Object

getBean(String

name)方法,其中参数

name为配置文件中bean的id值,返回值是IoC容器装配成功的bean对象。BeanFactroy采用延迟加载形式注入bean,即只有在使用某个bean(调用getBean()方法)时,才对该bean进行加载实例化。BeanFactory有很多子接口,在Java

EE应用中,建议使用其子接口ApplicationContext来替代BeanFactory,因为

ApplicationContext扩展了BeanFactory,不仅能实现BeanFactory所有功能,还扩展了一些企业应用中的特性。

ApplicationContext是接口,不能直接创建对象,可以使用其实现类创建对象,如ClassPathXmlApplicationContext、FileSystemXmlApplicationContext等。Application

Context与BeanFactory相反,它会在容器启动时,一次性创建所有的bean,即在容器启动时,就可以发现Spring框架中存在的配置错误。第31章SJparvianEgE核W心eb组开件发概述第31章SJparvianEgE核W心eb组开件发概述3.1

BeanFactory与ApplicationContext:例如,在ApplicationContext.xml中配置了bean后(在后续章节中介绍如何配置),通过如下代码使用bean:public

static

void

main(String[]

args)

{ApplicationContext

ctxt=

new

ClassPathXmlApplicationContext("applicationContext.xml");BasicDataSource

dataSource

=

(BasicDataSource)

txt.getBean("dataSource");Connection

conn=null;for(int

i=0;i<15;i++){try

{conn=dataSource.getConnection();System.out.println("connection

"+i+"

:

"+conn.hashCode());}

catch

(SQLException

e)

{e.printStackTrace();}}}在上述代码中,首先创建了ClassPathXmlApplicationContext对象,该对象依据配置文件ApplicationContext.xml获得

IoC容器的信息。3.1

BeanFactory与ApplicationContext:使用ClassPathXmlApplicationContext中的getBean方法获得id为dataSource的bean对象。接下来就可以通过获得的bean对象来获得连接,使用数据库连接池。可见,使用IoC容器装配对象后,在源代码中不需要再进行烦琐的编程,可以便捷地使用ApplicationContext中定义的getBean方法获得bean进行使用,对象完全交给容器管理。在了解了如何使用容器管理的bean后,下一节将学习如何定义bean的基本配置信息,以便IoC容器能够根据配置信息生成应用程序需要的bean。第31章SJparvianEgE核W心eb组开件发概述3.2

Spring

bean的基本配置:Spring框架的IoC容器所管理的对象称为bean,bean的元数据(基础信息)可以在XML中进行配置。除XML外,还有其他方式可以定义bean的元数据,包括使用Java属性文件、自定义编程等,目前XML配置bean还是最常用的方式。习惯上,bean的XML配置文件名字为ApplicationContext.xml,也可以任意命名为其他名字。配置文件中至少配置一个<bean></bean>,但是往往会有多个<bean>,都配置在<beans>下,配置文件模板如下所示:第31章SJparvianEgE核W心eb组开件发概述<?xml

version="1.0"

encoding="UTF-8"?><beans

xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.

org/schema/aop"xsi:schemaLocation="/schema/beans

/schema/beans/spring-beans-4.0.xsd

/schema/aop

/schema/aop/spring-aop-4.0.xsd"><bean

id="

"

class="

"></bean></beans>3.2

Spring

bean的基本配置:在<beans></beans>标签中配置多个<bean></bean>,配置bean时,必须指定的是id和class属性,其中id是该bean的唯一标记,上一节学习到的ApplicationContext可以使用getBean方法通过id值获取具体的bean对象进行使用。class属性定义该bean的类型,既可以是具体类,也可以是接口。每个bean基本都有不同的属性,需要为属性赋值,为属性赋值的具体方式有多种,将在第4章中详细介绍,此处演示最简单的赋值方法,代码如下所示:第31章SJparvianEgE核W心eb组开件发概述<bean

id="dataSource"

class="mons.dbcp.BasicDataSource"><property

name="driverClassName"><value>com.mysql.jdbc.Driver</value></property><property

name="url"><value>jdbc:mysql://localhost:3306/test</value></property><property

name="username"><value>root</value></property><property

name="password"><value>1234</value></property><property

name="maxActive"><value>10</value></property><property

name="initialSize"><value>2</value></property></bean>BasicDataSource

dataSource

=

new

BasicDataSource();dataSource.setDriverClassName("com.mysql.jdbc.Driver");dataSource.setUrl("jdbc:mysql://localhost:3306/test");dataSource.setUsername("root");dataSource.setPassword("1234");dataSource.setMaxActive(10);dataSource.setInitialSize(2);3.2

Spring

bean的基本配置:使用Spring框架后,就不再需要烦琐的Java编程来装配对象,只要直接从容器中获取使用即可,代码如下所示:第31章SJparvianEgE核W心eb组开件发概述public

static

void

main(String[]

args)

{ApplicationContext

ctxt

=

new

ClassPathXmlApplicationContext("applicationContext.xml");BasicDataSource

dataSource

=

(BasicDataSource)

txt.getBean("dataSource");}上述代码使用Spring框架的IoC容器来生成bean,并使用getBean方法获取对象。试想一下,如果dataSource对象的属性有变化,使用IoC容器只需要修改XML文件即可,dataSource对象就可以使用新的属性。否则,就需要修改每处创建

dataSource对象的源代码,才能保证修改成功。可见,使用Spring框架的IoC容器生成并管理bean对象,能提高应用程序的可扩展性及代码复用性。3.3

bean的作用域:使用XML配置bean的元数据,<bean></bean>节点描述了一个实例的基本特征,包括其类型、属性值等,如同一个实例的模板,根据这个模板,IoC容器就可以为应用程序创建出具体的bean实例。<bean>节点可以通过scope属性定义bean的作用域,scope的属性值有四个,如表3-1所示。第31章SJparvianEgE核W心eb组开件发概述属性值含义singleton永远使用一个唯一的bean对象,是scope的默认值prototype每次使用都构建一个新的bean对象request每次HTTP请求构建一个bean实例(在Web环境中生效)session在一个HTTP

Session中,永远使用一个唯一的bean实例(在Web环境中生效)3.3

bean的作用域:使用导引案例中的SalaryInfo类说明不同的作用域。在ApplicationContext.xml中配置两个bean,代码如下所示:在上述配置文件中,配置了两个bean,id为sInfo1的bean没有使用scope属性,则默认为singleton,id为sInfo2的bean使用scope属性,赋值为prototype。第31章SJparvianEgE核W心eb组开件发概述<bean

id="sInfo1"

class="com.chinasofti.salary.vo.SalaryInfo"><property

name="id"><value>1</value></property><property

name="basicSalary"><value>5000</value></property><property

name="meritPay"><value>2000</value></property><property

name="basis"><value>5000</value></property></bean><bean

id="sInfo2"

class="com.chinasofti.salary.vo.SalaryInfo"

scope="prototype"><property

name="id"><value>1</value></property><property

name="basicSalary"><value>5000</value></property><property

name="meritPay"><value>2000</value></property><property

name="basis"><value>5000</value></property></bean>3.3

bean的作用域:使用如下代码测试:在上述代码中,分别获得两个sInfo1实例,使用双等号判断引用是否相等。如果相等,则表示是同一个实例;如果不相等,则表示是两个实例。运行结果如下所示:第31章SJparvianEgE核W心eb组开件发概述public

static

void

main(String[]

args)

{ApplicationContext

ctxt=new

ClassPathXmlApplicationContext("scope.xml");SalaryInfo

s1=(SalaryInfo)

ctxt.getBean("sInfo1");SalaryInfos2=(SalaryInfo)ctxt.getBean("sInfo1");SalaryInfos3=(SalaryInfo)ctxt.getBean("sInfo2");SalaryInfo

s4=(SalaryInfo)

ctxt.getBean("sInfo2");System.out.println("s1==s2:

"+(s1==s2));System.out.println("s3==s4:

"+(s3==s4));}s1==s2:

trues3==s4:

false3.3

bean的作用域:可见,两个id为sInfo1的bean实例是同一个实例,因为默认是singleton作用域,所以表示单例,永远返回同一个实例。而

sInfo2的两个实例是不同的实例,因为scope是prototype,表示每次都返回一个新的实例。除了默认的singleton和prototype,还有request和session两个属性,需要在Web环境中测试使用,request表示在一个请求中使用同一个实例,session表示在一个会话中使用同一个实例。如果除了Spring框架预定义的四个作用域,还需要其他作用域,则可以通过实现org.springframework.beans.factory.config.Scope自定义作用域类。第31章SJparvianEgE核W心eb组开件发概述3.4实例化bean的方法:通过上一节的示例可见,使用IoC容器管理bean,主要包括实例化bean及装配bean两个方面。在装配bean之前,需要能够实例化bean。只要在XML中定义好bean的元数据,调用ApplicationContext的getBean方法就可以使用装配好的实例。在使用实例之前,该实例肯定已经被实例化。本节学习如何在XML文件中指定IoC容器实例化bean对象的不同方法。上述内容以SalaryInfo类为例,展示不同的实例化方法。值得注意的是,在实际应用中,SalaryInfo这样的实体类往往不会使用IoC容器进行管理,而DAO类、Service服务类等会使用IoC容器进行管理。IoC容器通常有以下三种实例化bean的方法。第31章SJparvianEgE核W心eb组开件发概述3.4实例化bean的方法:1.通过无参构造方法实例化在配置文件中,如果只使用id和class属性配置bean,则默认调用类的无参构造方法实例化。如下配置将调用SalaryInfo类的无参构造方法创建实例。代码如下所示:第31章SJparvianEgE核W心eb组开件发概述<bean

id="sInfo"

class="com.chinasofti.salary.vo.SalaryInfo"

scope="prototype"></bean>在配置文件中可以使用factory-method属性调用该静态工厂方法并创建实例。当使用sInfo3时,则调用SalaryInfo类中的

createSalaryInfo方法返回实例。代码如下所示:第31章SJparvianEgE核W心eb组开件发概述3.4实例化bean的方法:2.通过静态工厂方法实例化有些类中提供了静态的工厂方法返回实例,假设SalaryInfo类中有如下静态工厂方法:public

static

SalaryInfo

createSalaryInfo(){System.out.println("invoke

createSalaryInfo()");return

new

SalaryInfo();}<bean

id="sInfo3"

class="com.chinasofti.salary.vo.SalaryInfo"

factory-method="createSalaryInfo"></bean>第31章SJparvianEgE核W心eb组开件发概述3.4实例化bean的方法:3.通过非静态工厂方法实例化有些类中可能使用非静态工厂方法返回实例,假设存在一个类SalaryInfoFactory,其中提供了非静态的工厂方法以返回实例,代码如下所示:public

class

SalaryInfoFactory

{public

SalaryInfo

createSalaryInfo(){System.out.println("invoke

SalaryInfoFactory

createSalaryInfo()");return

new

SalaryInfo();}}在上述工厂类中,定义了非静态的工厂方法createSalaryInfo,返回实例SalaryInfo,接下来可以在XML中配置使用。<bean

id="factorybean"

class="com.chinasofti.test.SalaryInfoFactory"

></bean><bean

id="sInfo4"

factory-bean="factorybean"

factory-method="createSalaryInfo"></bean>3.4实例化bean的方法:上篇配置文件中,首先实例化了工厂类SalaryInfoFactory的实例factorybean,然后配置id为sInfo4的bean时,通过

factory-bean指定使用该工厂bean,并通过factory-method指定使用工厂方法createSalaryInfo实例化SalaryInfo的实例。当应用程序规模较大时,往往需要配置很多bean,那么可以根据逻辑相关配置到不同的XML文件中。例如本章示例中,使用到两个XML,分别是ApplicationContext.xml和Scope.xml文件,可以通过字符串数组传递参数,生成一个上下文对象,代码如下所示:如上代码所示,context对象可以获取两个XML文件中配置的bean。除此之外,也可以把多个XML文件引入一个XML文件中,代码如下所示:第31章SJparvianEgE核W心eb组开件发概述ApplicationContext

context

=

new

ClassPathXmlApplicationContext(new

String[]{"scope.xml",

"applicationContext.

xml"});<import

resource="applicaitonContext.xml"/><bean

id="sInfo1"

class="com.chinasofti.salary.vo.SalaryInfo">…在上述配置文件中,引入了ApplicationContext.xml,等同于形成一个XML文件,值得注意的是,<import>必须在所有<bean>定义之前使用。3.5第一个Spring框架实例:1.创建Java工程,引入Spring框架的核心包Spring框架可以在任何类型的工程中使用,使用Eclipse开发平台创建Java工程,右键单击工程名称,选择“属性”→

“build

path”→“libraries”→“Add

External

Jars”菜单命令,添加Spring框架的核心jar包(从官网下载Spring框架相关资源),Spring框架的jar包很多,目前用到的功能很少,所以只引入核心jar包即可第31章SJparvianEgE核W心eb组开件发概述3.5第一个Spring框架实例:2.创建案例中使用的Java类案例模拟操作系统可以自由选择不同的USB设备进行数据存储,先定义抽象类USBStorage,描述USB设备的基本特征,代码如下所示:第31章SJparvianEgE核W心eb组开件发概述public

abstract

class

USBStorage

{private

String

volumeLabel;public

String

getVolumeLabel()

{return

volumeLabel;}public

void

setVolumeLabel(String

volumeLabel)

{this.volumeLabel

=

volumeLabel;}public

abstract

void

writeData();}3.5第一个Spring框架实例:在上述抽象类USBStorage中定义了抽象方法writeData,需要在子类中实现。假设有U盘及移动硬盘两种USB设备,则定义两个子类,代码如下所示:在上述代码中定义了两个子类,分别描述U盘及移动硬盘,各自实现了不同的写数据方法。第31章SJparvianEgE核W心eb组开件发概述public

class

UDisk

extends

USBStorage

{public

void

writeData()

{System.out.println("向U盘中写入数据……");}}public

class

PortableHD

extends

USBStorage

{public

void

writeData()

{System.out.println("向移动硬盘中写入数据……");}}3.5第一个Spring框架实例:接下来定义操作系统类,操作系统会识别不同的移动设备,进行写数据操作,代码如下所示:第31章SJparvianEgE核W心eb组开件发概述public

class

OperationSystem

{USBStorage

storage;public

USBStorage

getStorage()

{return

storage;}public

void

setStorage(USBStorage

storage)

{this.storage

=

storage;}public

void

saveFile()

{System.out.println(storage.getVolumeLabel());storage.writeData();}}在上述代码中,OperationSystem类关联了抽象类USBStorage,可以根据需要,动态为USBStorage赋值为UDisk或PortableHD。3.5第一个Spring框架实例:3.在XML文件中定义beanOperationSystem实例总要使用一个USBStorage才能进行写文件操作,需要使用Spring框架的IoC容器来实例化并装配

OperationSystem类型的bean,在src目录下创建并编写firstdemo.xml文件,代码如下所示:在上述配置文件中,定义了UDisk类型的bean,id为udisk;定义了PortableHD类型的bean,id为protableHD;定义了类型为OperationSystem的bean,该bean需要一个属性storage,storage在类中定义的类型是抽象类型USBStorage,所以该抽象类的任意子类类型都可以赋值给storage。在上述配置文件中把udisk赋值给storage,也就是目前使用U盘作为移动存储设备。第31章SJparvianEgE核W心eb组开件发概述<bean

id="udisk"

class="com.chinasofti.firstdemo.UDisk"><property

name="volumeLabel"value="Jerry的U盘"/></bean><bean

id="portableHD"

class="com.chinasofti.firstdemo.PortableHD"><property

name="volumeLabel"value="Jerry的移动硬盘"/></bean><bean

id="os"

class="com.chinasofti.firstdemo.OperationSystem"><property

name="storage"

ref="udisk"></property></bean>3.5第一个Spring框架实例:4.测试使用定义Computer类,模拟进行存文件操作,代码如下所示:在上述代码中,使用id为os的bean,调用saveFile方法。由于os的storage使用了udisk,所以将使用UDisk类的方法存文件,运行结果如下所示:第31章SJparvianEgE核W心eb组开件发概述public

class

Computer

{public

static

void

main(String[]

args)

{ApplicationContext

ctx

=

new

ClassPathXmlApplicationContext("firstdemo.xml");OperationSystem

os

=

(OperationSystem)

ctx.getBean("os");os.saveFile();}}Jerry的U盘向U盘中写入数据……3.5第一个Spring框架实例:5.修改装配关系,再次测试假设目前需要使用移动硬盘进行存储,那么只修改firstdemo.xml中对os的配置即可,代码如下所示:在上述配置文件中,修改了os的装配关系,将移动硬盘ProtableHD实例赋值给storage属性。再次运行Computer类,运行结果如下所示:第31章SJparvianEgE核W心eb组开件发概述<bean

id="udisk"

class="com.chinasofti.firstdemo.UDisk"><property

name="volumeLabel"value="Jerry的U盘"/></bean><bean

id="portableHD"

class="com.chinasofti.firstdemo.PortableHD"><property

name="volumeLabel"value="Jerry的移动硬盘"/></bean><bean

id="os"

class="com.chinasofti.firstdemo.OperationSystem"><property

name="storage"

ref="portableHD"></property></bean>Jerry的移动硬盘向移动硬盘中写入数据……3.5第一个Spring框架实例:假设需要增加一种新的移动存储类,只要创建新类,继承抽象父类USBStorage,实现抽象方法,然后在XML中配置bean,赋值给OperationSystem的storage属性即可。对已有的源代码不需要做任何修改,就可以使用新的存储设备类。可见,使用Spring框架进行编程,把重要的实例都交给IoC容器生成并管理,能够提高应用的可扩展性。第31章SJparvianEgE核W心eb组开件发概述4.1依赖注入方式:Spring框架的IoC容器实现的核心功能是实例化bean并为bean的属性进行赋值,同时对bean的生命周期等进行管理,也就是为bean注入其需要的资源。在前面章节的示例代码中,没有深入学习注入方式,本节将详细学习Spring框架的依赖注入方式。依赖注入方式分为手动装配及自动装配两大类:手动装配需要明确指明每个属性的值;自动装配可以选择不同的策略,交代给IoC容器自动为bean寻找合适的属性值进行装配。自动装配虽然听起来非常便捷,但是存在一定的局限性,在自动查找的过程中,如果存在有歧义的属性,则会发生错误,对此将在后续章节中详细介绍。第41章SJparvianEgE框W架eb的开I发oC概容述器实现4.1依赖注入方式:如下所示的XML配置为手动装配方式:在上述XML文件中,使用手动装配方式配置service,指定了属性dao的值是前面配置好的id为dao的bean。第41章SJparvianEgE框W架eb的开I发oC概容述器实现<bean

id="dao"

class="com.chinasofti.salary.dao.EmployeeDAOJDBCImpl"></bean><bean

id="service"

class="com.chinasofti.salary.service.EmployeeServiceImpl"><property

name="dao"><ref

bean="dao"/></property></bean>4.1依赖注入方式:对于同样的service,可以使用如下方式自动装配:在上述XML文件中,使用autowire="byName"声明service使用通过名字自动装配的方式,自动将id为dao的bean装配给

service。自动装配需要IoC容器自行查找匹配的值进行装配,因此当bean较多时,容易出现混淆的情况。第41章SJparvianEgE框W架eb的开I发oC概容述器实现<bean

id="dao"

class="com.chinasofti.salary.dao.EmployeeDAOJDBCImpl"></bean><bean

id="service"

class="com.chinasofti.salary.service.EmployeeServiceImpl"autowire="byName"></bean>4.1.1手动装配:在一个Java类中,有两种方法可以为一个实例的属性进行赋值,即setter方法和构造方法。Spring框架的IoC容器也通过调用这两种方法为bean的属性赋值。下面使用SalaryInfo类说明两种方法的基本使用,代码如下所示:第41章SJparvianEgE框W架eb的开I发oC概容述器实现public

class

SalaryInfo

{private

int

id;private

double

basicSalary;private

double

meritPay;private

double

basis;get、set、构造省略在上述代码中,SalaryInfo类定义了四个属性,均为基本数据类型及String类型,并定义了无参构造方法及setter方法。4.1.1手动装配:第41章SJparvianEgE框W架eb的开I发oC概容述器实现(1)setter方法注入。setter方法注入指的是调用类中的setXXX方法为属性赋值,其中XXX为属性名字。在<bean></bean>标签中,使用<property></property>进行装配时,IoC容器则调用类的setter方法进行赋值。例如<property

name="basicSalary"><value>10000</value></property>,将调用类中的setBasicSalary方法,将10000作为形式参数传入,进行赋值<bean

id="sInfo"

class="com.chinasofti.salary.vo.SalaryInfo"><property

name="id"><value>1</value></property><property

name="basicSalary"><value>10000</value></property><property

name="meritPay"><value>5000</value></property><property

name="basis"><value>8000</value></property></bean>在上述配置中,对SalaryInfo类型的bean,使用<property></property>进行装配,即调用对应的setter方法,将value值传入赋值,如果没有对应的setter方法,则发生错误。值得一提的是,此处演示的类属性类型均为基本数据类型或String类型,为其指定具体值时使用<value></value>即可。然而,在实际应用开发过程中,很多属性的类型往往不仅是基本数

据类型和String类型,还可能是其他的引用类型、集合,甚至null等。当属性类型是其他类型时,就不再使用<valule></value>,而是使用其他标签进行装配,对此将在后续章节中介绍。4.1.1手动装配:第41章SJparvianEgE框W架eb的开I发oC概容述器实现(2)构造方法注入。构造方法注入指的是调用类中有参数的构造方法注入,例如SalaryInfo类中存在如下带参构造方法:public

SalaryInfo(int

id,

double

basicSalary,

double

meritPay,

double

basis)

{super();this.id

=

id;this.basicSalary

=

basicSalary;this.meritPay

=

meritPay;this.basis

=

basis;}使用<constructor-arg></constructor-arg>标签替代<property></property>进行装配,IoC容器将调用构造方法进行注入。<bean

id="sInfo2"

class="com.chinasofti.salary.vo.SalaryInfo"><constructor-arg

type="int"><value>1</value></constructor-arg><constructor-arg

type="double"><value>10000</value></constructor-arg><constructor-arg

type="double"><value>5000</value></constructor-arg><constructor-arg

type="double"><value>8000</value></constructor-arg></bean>4.1.1手动装配:在上述XML文件中,使用<constructor-arg></constructor-arg>注入bean,构造方法有多个参数,根据指定参数类型type的值,IoC容器会调用匹配的构造方法进行赋值。在上述配置中,IoC容器会调用构造方法SalaryInfo(int,double,double,double)进行赋值。另外,也可以指定构造方法参数的索引值来进行注入,索引值从0开始,代码如下所示:第41章SJparvianEgE框W架eb的开I发oC概容述器实现<bean

id="sInfo3"

class="com.chinasofti.salary.vo.SalaryInfo"><constructor-arg

index="0"><value>1</value></constructor-arg><constructor-arg

index="1"><value>8000</value></constructor-arg><constructor-arg

index="2"><value>3000</value></constructor-arg><constructor-arg

index="3"><value>8000</value></constructor-arg></bean>在上述XML文件中,使用索引值指定构造方法的参数顺序进行赋值。值得一提的是,由于一个类可能存在多个构造方法,所以使用构造方法赋值时可能存在歧义,不如setter方法明确,因此建议使用setter方法。第41章SJparvianEgE框W架eb的开I发oC概容述器实现4.1.2自动装配:自动装配(autowire)可以使XML文件更为精简。例如,导引案例中的service需要关联dao,也就是使用service实例必须为其装配一个dao实例,dao实现类代码如下所示:public

class

EmployeeDAOJDBCImpl

implements

EmployeeDAO

{@Overridepublic

Employee

selectByNamePwd(String

loginName,

String

empPwd)

{//省略其他代码……service实现类代码如下所示:public

class

EmployeeServiceImpl

implements

EmployeeService

{//关联dao对象private

EmployeeDAO

dao;//无参构造方法public

EmployeeServiceImpl()

{super();}//创建service对象时,为dao对象赋值public

EmployeeServiceImpl(EmployeeDAO

dao)

{this.dao

=

dao;}//setter方法public

void

setDao(EmployeeDAO

dao)

{this.dao

=

dao;}4.1.2自动装配:service实现类关联dao对象,名字为dao,类型为EmployeeDAO。在使用service实例前,必须为其属性dao赋值。除使

用上一节中的<property>及<constructor-arg>调用setter方法和构造方法进行手动装配外,还可以使用自动装配。自动装配有两种常用的方式,即通过类型的byType方式和通过名字的byName方式。(1)byType方式自动装配。byType方式自动装配指的是根据属性类型自动检测装配,代码如下所示:在上述XML文件中,使用byType方式自动装配service,IoC容器将查找service对应类EmployeeServiceImpl中的setter方法,找到public

void

setDao(EmployeeDAO

dao)方法,其参数类型是EmployeeDAO,则接下来在XML中查找类型为EmployeeDAO的bean,找到一个id为dao的bean,类型是EmployeeDAOJDBCImpl。由于EmployeeDAOJDBCImpl是EmployeeDAO的子类,所以dao是EmployeeDAO类型的bean,IoC容器就自动将dao注入service使用。如果XML中有多个类型是EmployeeDAO的bean,则会报错。第41章SJparvianEgE框W架eb的开I发oC概容述器实现<bean

id="dao"

class="com.chinasofti.salary.dao.EmployeeDAOJDBCImpl"></bean><bean

id="service"

class="com.chinasofti.salary.service.EmployeeServiceImpl"

autowire="byType"></bean>4.1.2自动装配:(2)byName方式自动装配。byName方式自动装配指的是根据属性名字自动检测装配,代码如下所示:在上述XML文件中,对id为service的bean声明了autowire="byName",IoC容器将检测EmployeeServiceImpl中的setter方法,找到public

void

setDao(EmployeeDAO

dao)方法。因为方法名是setDao,所以IoC容器认为属性名字是dao,则到XML中查找名字是dao的bean,找到后装配给service,完成byName方式的自动装配。第41章SJparvianEgE框W架eb的开I发oC概容述器实现<bean

id="dao"

class="com.chinasofti.salary.dao.EmployeeDAOJDBCImpl"></bean><bean

id="service"

class="com.chinasofti.salary.service.EmployeeServiceImpl"

autowire="byName"></bean>4.2不同类型的属性装配:在上面章节中,指定具体属性值的时候,使用的示例代码中的属性类型都是基本数据类型或String类型。在实际应用中,属性类型可以多种多样,可以归纳为基本数据类型和String类型、其他的bean类型、集合类型、null。本节学习每种类型的不同配置方法。(1)基本数据类型和String类型。基本数据类型和String类型在上面章节中已经多次使用,使用<value></value>直接赋值即可,不再赘述。第41章SJparvianEgE框W架eb的开I发oC概容述器实现第41章SJparvianEgE框W架eb的开I发oC概容述器实现4.2不同类型的属性装配:(2)其他bean类型。如果bean的属性不是基本数据类型或String类型,而是其他的bean,则不能使用<value></value>配置,而采用另外两种配置方式,分别为外部bean和内部bean。依然以上述的EmployeeDAO及EmployeeService为例,使用手动装配方式来装配service。service需要一个EmployeeDAO类型的属性,在XML中已经定义了一个类型为EmployeeDAO的bean,所以可以把这个bean注入service。代码如下所示:<bean

id="dao"

class="com.chinasofti.salary.dao.EmployeeDAOJDBCImpl"></bean><bean

id="service"

class="com.chinasofti.salary.service.EmployeeServiceImpl"><property

name="dao"><ref

bean="dao"/></property></bean>在上述XML中,使用<ref

bean="dao"/>为service注入属性,使用到已经定义好的id为dao的bean,这样的bean称为外部bean。注入外部bean还有一个等价的方式,代码如下所示:<bean

id="dao"

class="com.chinasofti.salary.dao.EmployeeDAOJDBCImpl"></bean><bean

id="service"

class="com.chinasofti.salary.service.EmployeeServiceImpl"><property

name="dao"

ref="dao"></property></bean>4.2不同类型的属性装配:两种方式完全等价,都是将一个已经定义好的bean注入另一个bean中,这种外部bean可以被注入多个bean中。如果某个

bean不会被多个bean使用,则可以声明为内部bean,代码如下所示:在上述XML中,使用内部bean注入service的属性dao,比起外部bean,内部bean只能在当前的bean中使用,不能被其他

bean引用。第41章SJparvianEgE框W架eb的开I发oC概容述器实现<bean

id="service"

class="com.chinasofti.salary.service.EmployeeServiceImpl"><property

name="dao"><bean

class="com.chinasofti.salary.dao.EmployeeDAOJDBCImpl"></bean></property></bean>4.2不同类型的属性装配:(3)集合类型。在实际应用中,类和类之间可能是一对多的关联关系,那么就需要使用集合类型来持有“多”的一方的对象。例如,存在

Order类和Item类,Order类中关联多个Item实例,因此使用List集合来实现这样的一对多关联关系,代码如下所示:当类的属性是集合类型时,也可以使用IoC容器进行注入。常用的集合类型有四种,即List、Set、Map及Properties,本节将分别介绍这四种集合类型的配置方式。第41章SJparvianEgE框W架eb的开I发oC概容述器实现public

class

Order

{private

String

id;

private

Customer

customer;private

List<Item>

items;//省略其他代码……4.2不同类型的属性装配:①<list>。如果属性是List或数组类型,IoC容器将使用<list>元素进行配置。<list>元素中的子元素可以根据该List或数组对象中存储的元素类型进行选择,可以是<value>、<ref>、<null>、<list>等。代码如下所示:第41章SJparvianEgE框W架eb的开I发oC概容述器实现<bean

id="item1"

class="com.chinasofti.cart.Item"><property

name="itemid"><value>1</value></property><property

name="name"><null/></property><property

name="price"><value>34.5</value></property></bean><bean

id="item2"

class="com.chinasofti.cart.Item"><property

name="itemid"><value>2</value></property><property

name="name"><value>DVD</value></property><property

name="price"><value>23</value></property></bean><bean

id="cart"

class="com.chinasofti.cart.Order"><property

name="id"><value>1</value></property><property

name="customer"><ref

bean="customer"/></property><property

name="items"><list><ref

bean="item1"/><ref

bean="item2"/></list></property></bean>使用<list>元素将item1和item2添加到集合items中,赋值给属性items。4.2不同类型的属性装配:②<set>。当集合采用Set类型的集合类时,则采用<set>元素进行装配,用法与<list>相同。③<map>。当集合采用Map类型的映射类时,则采用<map>元素进行装配。代码及语法结构如下所示:第41章SJparvianEgE框W架eb的开I发oC概容述器实现<bean><property

name=""><map><entry><key><value></value></key><ref/></entry></map></property></bean><map>元素下可以有多对<entry></entry>条目元素,每个条目配置Map的一对键值对。其中<key>用来配置当前条目

的键值,<key>元素内可以使用<value>、<ref>、<list>和<set>等各种类型元素,在上述示例中使用<value>。键值对中的值也

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论