??xml version="1.0" encoding="utf-8" standalone="yes"?> Spring AOP ?IOC 容器入门 U别Q?初 Naveen Balani (naveenbalani@rediffmail.com), 技术架构师, Webify Solutions 2005 q?8 ?18 ?/p>
Spring 是一个开源框Ӟ是ؓ了解决企业应用程序开发复杂性而创建的。框架的主要优势之一是其分层架构,分层架构允许您选择使用哪一个组Ӟ同时?J2EE 应用E序开发提供集成的框架?/p>
在这由三部分组成的 Spring pd 的第 1 部分中,我将介绍 Spring 框架。我先从框架底层模型的角度描q该框架的功能,然后讨Z个最有趣的模块:Spring 面向斚w~程QAOPQ和控制反{ QIOCQ?容器。接着用几个示例演C?IOC 容器在典型应用程序用例场景中的应用情c这些示例还成为本pd后面部分q行的展开式讨论的基础Q在本文的后面部分,介l?Spring 框架通过 Spring AOP 实现 AOP 构造的方式?/p>
请参?下蝲Q下?Spring 框架?Apache AntQ运行本pd的示例应用程序需要它们?/p>
Spring 框架是一个分层架构,?7 个定义良好的模块l成。Spring 模块构徏在核心容器之上,核心容器定义了创建、配|和理 bean 的方式,如图 1 所C?/p>
l成 Spring 框架的每个模块(或组Ӟ都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下Q?
Spring 框架的功能可以用在Q?J2EE 服务器中Q大多数功能也适用于不受管理的环境。Spring 的核心要ҎQ支持不l定到特?J2EE 服务的可重用业务和数据访问对象。毫无疑问,q样的对象可以在不同 J2EE 环境 QWeb ?EJBQ、独立应用程序、测试环境之间重用? 控制反{模式Q也UC依赖性介入)的基本概忉|Q不创徏对象Q但是描q创建它们的方式。在代码中不直接与对象和服务q接Q但在配|文件中描述哪一个组仉要哪一Ҏ务。容?Q在 Spring 框架中是 IOC 容器Q?负责这些联pd一赗?/p>
在典型的 IOC 场景中,容器创徏了所有对象,q设|必要的属性将它们q接在一P军_什么时间调用方法。下表列Z IOC 的一个实现模式?/p>
Spring 框架?IOC 容器采用cd 2 和类? 实现?/p>
面向斚w的编E?/em>Q即 AOPQ是一U编E技术,它允许程序员Ҏ切关注点或横切典型的职责分界U的行ؓQ例如日志和事务理Q进行模块化。AOP 的核心构造是斚wQ它那些媄响多个类的行为封装到可重用的模块中?/p>
AOP ?IOC 是补充性的技术,它们都运用模块化方式解决企业应用E序开发中的复杂问题。在典型的面向对象开发方式中Q可能要日志记录语句放在所有方法和 Java cM才能实现日志功能。在 AOP 方式中,可以反过来将日志服务模块?/em>Qƈ以声明的方式它们应用到需要日志的lg上。当Ӟ优势是 Java cM需要知道日志服务的存在Q也不需要考虑相关的代码。所以,?Spring AOP ~写的应用程序代码是松散耦合的?/p>
AOP 的功能完全集成到?Spring 事务理、日志和其他各种Ҏ的上下文中?/p>
Spring 设计的核心是 bean 工厂的概忉| Spring 作ؓ IOC 容器的基。IOC 处理事情的责Q从应用程序代码{Ud框架。正如我在下一个示例中演示的那PSpring 框架使用 JavaBean 属性和配置数据来指出必设|的依赖关系?/p>
因ؓ ?XML 文g中定义的 Bean 是被消极加蝲的,q意呛_需?bean 之前Qbean 本n不会被初始化。要? 每个 bean 的定义都可以?POJO Q用cd?JavaBean 初始化属性定义) ? 理解控制反{最单的方式是看它的实际应用。在对由三部分组成的 Spring pd 的第 1 部分q行ȝӞ我用了一个示例,演示了如何通过 Spring IOC 容器注入应用E序的依赖关p(而不是将它们构徏q来Q?/p>
我用开启在U信用帐L用例作ؓL。对于该实现Q开启信用帐戯求用户与以下服务q行交互Q?
对于q个CZQ我假设服务已经存在Q理想的情况是用松散耦合的方式把它们集成在一赗以下清单显CZ三个服务的应用程序接口?/p>
清单 3 所C的信用U别评定接口提供了信用历史信息。它需要一个包含客户信息的 信用链接接口信用历史信息与银行信息Q如果需要的话)q接在一Pq插入用L信用卡信息。信用链接接口是一个远E服务,它的查询是通过 q些接口׃之后Q接下来要考虑的就是如何用松散耦合方式它们集成在一赗在 清单 6 中可以看C用卡帐户用例的实现?/p>
注意Q所有的 setter Ҏ都是?Spring 的配|?bean 实现的。所有的依赖关系 Q也是三个接口Q都可以?Spring 框架用这?bean 注入?code>createCreditCardAccount() Ҏ会用服务L行其余实现。在 清单 7 中可以看?Spring 的配|文件。我用箭头突Zq些定义? 要运行示例应用程序,首先必须 下蝲 Spring 框架 及其所有依赖文件。接下来Q将框架释放刎ͼ比如_盘 c:\Q这会创?C:\spring-framework-1.2-rc2 Q适用于当前发行版本) q样的文件夹。在l箋后面的操作之前,q必M载和释放 Apache Ant?/p>
接下来,源代码释放到文件夹Q例?c:\ 盘,然后创徏 SpringProject。将 Spring 库(?C:\spring-framework-1.2-rc2\dist 下的 spring.jar ?C:\spring-framework-1.2-rc2\lib\jakarta-commons 下的 commons-logging.jarQ复制到 SpringProject\lib 文g夹中。完成这些工作之后,有了必需的构Z赖关p集?/p>
打开命o提示W,当前目录切换到 SpringProjectQ在命o提示W中输入以下命oQ?code>build? q会构徏q运? 在这由三部分组成的 Spring pd 的第一文章中Q我介绍?Spring 框架的基。我从讨论组?Spring 分层架构?7 个模块开始,然后深入介绍了其中两个模块:Spring AOP ?IOC 容器?/p>
׃学习的最x法是实践Q所以我用一个工作示例介l了 IOC 模式 Q像 Spring ?IOC 容器实现的那P如何用松散耦合的方式将分散的系l集成在一赗在q个CZ中可以看刎ͼ依赖关pL服务注入工作中的信用卡帐户应用程序,要比从头开始构建它们容易得多?/p>
Ll关注这一pd的下一文章,我将在这里学习的知识基础上,介绍 Spring AOP 模块如何在企业应用程序中提供持久支持Qƈ让您开始了?Spring MVC 模块和相x件?/p>
文选项
在这׃部分l成的介l?Spring 框架的系列文章的W一期中Q将开始学习如何用 Spring 技术构量的、强壮的 J2EE 应用E序。developerWorks 的定期投Eh Naveen Balani 通过介绍 Spring 框架开始了他由三部分组成的 Spring pdQ其中还介l?Spring 面向斚w的编E(AOPQ和控制反{QIOCQ容器?/blockquote>
?1. Spring 框架?7 个模?/strong>
BeanFactory
Q它是工厂模式的实现?code>BeanFactory 使用控制反{ QIOCQ?模式应用程序的配置和依赖性规范与实际的应用程序代码分开?/li>
回页?/strong>
cd 1
服务需要实C门的接口Q通过接口Q由对象提供q些服务Q可以从对象查询依赖性(例如Q需要的附加服务Q?/td>
cd 2
通过 JavaBean 的属性(例如 setter ҎQ分配依赖?/td>
cd 3
依赖性以构造函数的形式提供Q不?JavaBean 属性的形式公开
回页?/strong>
org.springframework.beans
包,它的设计目标是与 JavaBean lg一起用。这个包通常不是qL接用,而是由服务器其用作其他多数功能的底层中介。下一个最高抽象?BeanFactory
接口Q它是工厂设计模式的实现Q允讔R过名称创徏和检索对象?code>BeanFactory 也可以管理对象之间的关系?/p>
BeanFactory
支持两个对象模型?/p>
org.springframework.beans.factory.BeanFactory
是一个简单接口,所以可以针对各U底层存储方法实现。最常用?BeanFactory
定义?XmlBeanFactory
Q它Ҏ XML 文g中的定义装入 beanQ如清单 1 所C?/p>
清单 1. XmlBeanFactory
BeanFactory factory = new XMLBeanFactory(new FileInputSteam("mybean.xml"));
BeanFactory
?beanQ只需调用 getBean()
ҎQ传入将要检索的 bean 的名U即可,如清?2 所C?/p>
清单 2. getBean()
MyBean mybean = (MyBean) factory.getBean("mybean");
FactoryBean
?code>FactoryBean 接口Z?Spring 框架构徏的应用程序添加了一个间接的U别?/p>
回页?/strong>
回页?/strong>
清单 3. CreditRatingInterface
public interface CreditRatingInterface {
public boolean getUserCreditHistoryInformation(ICustomer iCustomer);
}
Customer
对象。该接口的实现是?CreditRating
cL供的?/p>
清单 4. CreditLinkingInterface
public interface CreditLinkingInterface {
public String getUrl();
public void setUrl(String url);
public void linkCreditBankAccount() throws Exception ;
}
getUrl()
Ҏq行的。URL ?Spring 框架?bean 配置机制讄Q我E后会讨论它。该接口的实现是?CreditLinking
cL供的?/p>
清单 5. EmailInterface
public interface EmailInterface {
public void sendEmail(ICustomer iCustomer);
public String getFromEmail();
public void setFromEmail(String fromEmail) ;
public String getPassword();
public void setPassword(String password) ;
public String getSmtpHost() ;
public void setSmtpHost(String smtpHost);
public String getUserId() ;
public void setUserId(String userId);
}
EmailInterface
负责向客户发送关于客户信用卡状态的电子邮g。邮仉|参敎ͼ例如 SMPT L、用户名、口令)由前面提到的 bean 配置机制讄?code>Email cL供了该接口的实现?/p>
回页?/strong>
回页?/strong>
CreateCreditAccountClient
c,cȝq行创?Customer
cd象ƈ填充它,q会调用 CreateCreditCardAccount
cd建ƈ链接信用卡帐戗?code>CreateCreditAccountClient q会通过 ClassPathXmlApplicationContext
装入 Spring 配置文g。装?bean 之后Q就可以通过 getBean()
Ҏ讉K它们了,如清?8 所C?/p>
清单 8. 装入 Spring 配置文g
ClassPathXmlApplicationContext appContext =
new ClassPathXmlApplicationContext(new String[] {
"springexample-creditaccount.xml"
});
CreateCreditCardAccountInterface creditCardAccount =
(CreateCreditCardAccountInterface)
appContext.getBean("createCreditCard");
回页?/strong>
]]>
本文主要讲了Spring 声明式事务让我们从复杂的Hibernate事务处理中得到解脱?/p>
使得我们再也无需要去处理获得q接、关闭连接、Hibernate事务提交和回滚等q些操作。再也无< font color="#ff0000">需要我们在与事务相关的Ҏ中处理大量的try…catch…finally代码< /font>?/p>
我们在用Spring 声明式事务时Q有一个非帔R要的概念是事务属性。事务属性通常׃务的传播行ؓQ事务的隔离U别Q事务的时值和事务只读标志l成。我们在q行事务划分Ӟ需要进行Hibernate事务定义Q也是配置Hibernate事务的属性?/p>
Spring Hibernate?gt;TransactionDefinition 接口中定义这些属?以供PlatfromTransactionManager使用, PlatfromTransactionManager是spring Hibernate事务理的核心接口?
代码
- TransactionDefinition publicinterfaceTransactionDefinition {
- intgetPropagationBehavior();
- intgetIsolationLevel();
- intgetTimeout();
- booleanisReadOnly();
- }
getTimeout()ҎQ它q回事务必须在多秒内完成?
isReadOnly(),事务是否只读Q事务管理器能够Ҏq个q回D行优化,保事务是只ȝ?
getIsolationLevel()Ҏq回事务的隔ȝ别,事务理器根据它来控制另外一个事务可以看到本事务内的哪些数据?
在TransactionDefinition接口中定义了五个不同的事务隔ȝ?
1) ISOLATION_DEFAULT q是一?PlatfromTransactionManager默认的隔ȝ别,使用数据库默认的事务隔离U别.另外四个与JDBC的隔ȝ别相对应
2) ISOLATION_READ_UNCOMMITTEDq是事务最低的隔离U别Q它充许别外一个事务可以看到这个事务未提交的数据。这U隔ȝ别会产生脏读Q不可重复读和像读?/p>
3) ISOLATION_READ_COMMITTED 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这U事务隔ȝ别可以避免脏d玎ͼ但是可能会出C可重复读和像读?/p>
4) ISOLATION_REPEATABLE_READ q种事务隔离U别可以防止脏读Q不可重复读。但是可能出现像读。它除了保证一个事务不能读取另一个事务未提交的数据外Q还保证了避免下面的情况产生(不可重复?
在TransactionDefinition接口中定义了七个事务传播行ؓ:
1) < span style="color: #000000;"> PROPAGATION_REQUIRED 如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事?
2) PROPAGATION_SUPPORTS 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执?
3) PROPAGATION_MANDATORY 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务Q则抛出?
4)PROPAGATION_REQUIRES_NEW L开启一个新的事务。如果一个事务已l存在,则将q个存在的事务挂?
5) PROPAGATION_NOT_SUPPORTEDL非事务地执行Qƈ挂vM存在的事?
6) PROPAGATION_NEVERL非事务地执行Q如果存在一个活动事务,则抛出异?
7) PROPAGATION_NESTED如果一个活动的事务存在Q则q行在一个嵌套的事务? 如果没有zd事务, 则按 TransactionDefinition.PROPAGATION_REQUIRED 属性执?