﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Java Votary-随笔分类-Springframework</title><link>http://www.blogjava.net/ericwang/category/5053.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 13:12:31 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 13:12:31 GMT</pubDate><ttl>60</ttl><item><title>在SPRING中实现事务暂停</title><link>http://www.blogjava.net/ericwang/archive/2005/12/16/24299.html</link><dc:creator>Dion</dc:creator><author>Dion</author><pubDate>Fri, 16 Dec 2005 14:39:00 GMT</pubDate><guid>http://www.blogjava.net/ericwang/archive/2005/12/16/24299.html</guid><wfw:comment>http://www.blogjava.net/ericwang/comments/24299.html</wfw:comment><comments>http://www.blogjava.net/ericwang/archive/2005/12/16/24299.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ericwang/comments/commentRss/24299.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ericwang/services/trackbacks/24299.html</trackback:ping><description><![CDATA[<center><b><span style="font-size: 20px;">在SPRING中实现事务暂停</span></b></center><br><center>作者：Juergen Hoeller</center><br><center>译者:<a href="http://www.matrix.org.cn/user.shtml?username=xMatrix" target="_new">xMatrix</a></center><br><br><br><br><br><span style="color: Red;">版权声明：任何获得Matrix授权的网站，转载时请<b>务必</b>以超链接形式标明文章原始出处和作者信息及本声明</span><br>作者:Juergen Hoeller;<a href="http://www.matrix.org.cn/user.shtml?username=xMatrix" target="_new">xMatrix</a><br>原文地址:<a href="http://dev2dev.bea.com/pub/a/2005/07/spring_transactions.html" target="_new">http://dev2dev.bea.com/pub/a/2005/07/spring_transactions.html</a><br>中文地址:<a href="http://www.matrix.org.cn/resource/article/44/44054_Transaction+Spring.html" target="_new">http://www.matrix.org.cn/resource/article/44/44054_Transaction+Spring.html</a><br>关键词： Transaction Suspension Spring<br><br><b><span style="font-size: 16px;">摘要</span></b><br><br>Spring
框架是一个流行的基于轻量级控制反转容器的Java/J2EE应用框架，尤其在数据访问和事务管理方面的能力是众所周知的。Spring的声明性事务分离
可以应用到任何POJO目标对象，并且包含所有EJB基于容器管理事务中的已声明事务。后台的事务管理器支持简单的基于JDBC的事务和全功能的基于
JTA的J2EE事务。<br><br>这篇文章详细的讨论了Spring的事务管理特性。重点是如何在使用JTA作为后台事务策略的基础上让POJO利
用Spring的声明性事务，这也显示了Spring的事务服务可以无缝地与J2EE服务器（如BEA WebLogic
Server的事务协调器）的事务协调器进行交互，作为EJB CMT传统事务分离方式的一个替代者。<br><br><b><span style="font-size: 16px;">POJO的声明性事务</span></b><br><br>作为Spring声明性事务分离方式的样例，让我们来看一下Spring的样例应用PetClinic的中心服务外观中的配置：<br><b>清单1：</b><br><pre title="pre code" class="overflow">&lt;bean id="dataSource" <br>&nbsp;&nbsp; class="org.springframework.jndi.JndiObjectFactoryBean"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="jndiName"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;java:comp/env/jdbc/petclinic&lt;/value&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br>&lt;/bean&gt;<br><br>&lt;bean id="transactionManager" <br>&nbsp;&nbsp; class="org.springframework.transaction.jta.JtaTransactionManager"/&gt;<br><br>&lt;bean id="clinicTarget" <br>&nbsp;&nbsp; class="org.springframework.samples.petclinic.jdbc.JdbcClinic"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="dataSource"&gt;&lt;ref bean="dataSource"/&gt;&lt;/property&gt;<br>&lt;/bean&gt;<br><br>&lt;bean id="clinic" <br>&nbsp;&nbsp; class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="transactionManager"&gt;&lt;ref bean="transactionManager"/&gt;&lt;/property&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="target"&gt;&lt;ref bean="clinicTarget"/&gt;&lt;/property&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="transactionAttributes"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;props&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;prop key="load*"&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;prop key="store*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/props&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt;<br>&lt;/bean&gt;</pre><br><br>他遵循Spring的标准XMLBean定义格式。定义了：<br>1、一个DataSource引用，指向一个JNDI位置—在J2EE服务器管理下这将从JNDI环境中获取特定的DataSource。<br>2、一个应用服务实现—这是一个POJO，封装了业务和数据访问逻辑。在这里实现了应用中的Clinic服务接口。<br>3、一个应用服务的事务代理—这个代理为目标服务定义了事务属性，匹配特定的方法名模式并为之创建相应的事务。在实际的事务管理中，代理指向一个PlatformTransactionManager实现。<br><span style="color: Red;">注意</span>：除了显式的代理定义，Spring还支持自动代理机制和通过Commons Attributes或J2SE 5.0注解实现源程序级的元数据使用。这些可选方法的讨论超过了本文的范围。可以参考Spring的文档来了解相关细节。<br><br><br>业务接口和业务实现是特定于应用的并且不需要关心Spring或者Spring的事务管理。普通Java对象可以作为服务的目标对象，而且任何普通Java接口可以作为服务的接口。下面是一个Clinic接口的示例：<br><b>清单2：</b><br><pre title="pre code" class="overflow">public interface Clinic {<br>&nbsp;&nbsp;&nbsp;&nbsp;Pet loadPet(int id);<br>&nbsp;&nbsp;&nbsp;&nbsp;void storePet(Pet pet);<br>&nbsp;&nbsp;&nbsp;&nbsp;...<br>}</pre><br><br><br>这个接口的实现如下显示，假设他使用JDBC来执行必要的数据访问。他通过bean属性的设置方法来获取JDBC的DataSource;这与上面的配置中的dataSource属性定义相对应。<br><b>清单3：</b><br><pre title="pre code" class="overflow">public class JdbcClinic implements Clinic {<br><br>&nbsp;&nbsp;&nbsp;&nbsp;private DataSource dataSource;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;public void setDataSource(DataSource dataSource) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.dataSource = dataSource;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;public Pet loadPet(int id) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Connection con = this.dataSource.getConnection();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch (SQLException ex) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;public void storePet(Pet pet) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Connection con = this.dataSource.getConnection();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch (SQLException ex) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;...<br>}</pre><br><br> <br>如你所见，代码相当直接。我们使用一个简单的Java对象，而事务管理由事务代理来处理，这个我们会在下面讨论。<br>注意在PetClinic示例应用中实际的基于JDBC的Clinic实现利用了Spring的JDBC支持类来避免直接使用JDBC的API。虽然Spring的事务管理也可以与普通的基于JDBC实现一起工作，就向上面的示例。<br><br><b>定义事务代理</b><br>除了JdbcClinic实例以外，配置中也定义了一个事务代理。如果愿意这个代理所暴露的实际接口也可以显式定义。默认情况下，所有由目标对象实现的接口都暴露出来，在这个例子中就是应用的Clinic服务接口。<br><br>从客户端的观点来看，"clinic" bean只是这个应用的Clinic接口的实现。客户端不需要知道这会被一个事务代理所处理。这就是接口的能力：一个直接的目标对象的引用可以容易的被一个实现相同接口的代理所代替—在这儿就是一个隐式创建事务的代理。<br>代理的具体事务行为会由为根据特定的方法或方法命名模式而定义的事务属性来驱动，就像下面的例子所示：<br><b>清单3：</b><br><pre title="pre code" class="overflow">&lt;prop key="load*"&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;<br>&lt;prop key="store*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;</pre><br><br>Key属性决定代理将为方法提供什么样的事务行为。这个属性的最重要部分就是事务传播行为。下面是一些可选的属性值：<br>1、PROPAGATION_REQUIRED --支持当前的事务，如果不存在就创建一个新的。这是最常用的选择。<br>2、PROPAGATION_SUPPORTS --支持当前的事务，如果不存在就不使用事务。<br>3、PROPAGATION_MANDATORY --支持当前的事务，如果不存在就抛出异常。<br>4、PROPAGATION_REQUIRES_NEW --创建一个新的事务，并暂停当前的事务（如果存在）。<br>5、PROPAGATION_NOT_SUPPORTED --不使用事务，并暂停当前的事务（如果存在）。<br>6、PROPAGATION_NEVER --不使用事务，如果当前存在事务就抛出异常。<br>7、PROPAGATION_NESTED --如果当前存在事务就作为嵌入事务执行，否则与PROPAGATION_REQUIRED类似。<br><br>前6
个事务策略与EJB的CMT类似，而且使用相同的常量名，因此对EJB开发人员来说是很亲切的。第7个策略PROPAGATION_NESTED是
Spring提供的一个变体：他需要事务管理器(如DataSourceTransactionManager)提供类似JDBC3.0那样的保存点
API来嵌套事务行为或者通过<br>JTA支持嵌套事务。<br><br>事务属性中的readOnly标识指示相应的事务应该作为一个只读事务来优化。这是一个优化提示：一些事务策略在这种情况下可以得到很好的性能优化，如使用ORM工具如Hibernate或TopLink时避免脏数据检查（“flush”尝试）。<br><br>在事务属性中还有一个“timeout”选项来定义事务的超时秒数。在JTA中，这个属性会简单地传递给J2EE服务器的事务协调器并被正确地解释。<br><br><b>使用事务代理</b><br>在
运行时，客户端会取得一个“clinic”引用并转换为Clinic接口，然后调用如loadPet或storePet方法。这就隐式地使用了
Spring的事务代理，通过“事务解释器”在目标对象中注册；这样一个新的事务就创建了，然后具体的工作就会代理给JdbcClinic的目标方法。<br>图1示例了一个使用“建议链”并到达最后目标的AOP代理的潜在概念。在这个示例中，唯一的建议是一个事务解释器用来包装目标方法的事务行为。这是一种用来在声明性事务功能下使用的基于代理的AOP。<br> <br><br><img src="http://www.matrix.org.cn/resource/upload/forum/2005_12_16_002248_zxcVMhvTna.gif" alt="" style="display: inline;" onmouseover="javascript:ImgShowTip(this);" onload="javascript:ImgLoad(this);" onclick="javascript:ImgClick(this);" border="0"><br>Figure 1. An AOP proxy with an advisor chain and a target at the end<br><br>例如，一个PetClinic应用的WEB层组件可以执行ServletContext定位来获取Spring WebApplicationContext的引用并且获取受管理的“clinic”BEAN：<br><b>清单4：</b><br><pre title="pre code" class="overflow">WebApplicationContext ctx = <br>&nbsp;&nbsp; WebApplicationContexUtils.getWebApplicationContext(servletContext);<br>Clinic clinic = (Clinic) ctx.getBean("clinic);<br><br>Pet pet = new Pet();<br>pet.setName("my new cat");<br><br>clinic.storePet(pet);</pre><br><br>在
调用storePet()之前，Spring的事务代理隐式地创建一个事务。当storePet()调用返回时，事务将提交或回滚。缺省情况下任何
RuntimeException或Error将导致回滚。实际的提交或回滚可以是可以定义的：Spring的事务属性支持“回滚规则”的概念。<br><br>例如，我们可以可以引入一个强制的PetClinicException并且告诉事务代理在抛出异常时回滚：<br><b>清单5：</b><br><pre title="pre code" class="overflow">&lt;prop key="load*"&gt;PROPAGATION_REQUIRED,readOnly,-PetClinicException&lt;/prop&gt;<br>&lt;prop key="store*"&gt;PROPAGATION_REQUIRED,-PetClinicException&lt;/prop&gt;</pre><br><br>这儿也有一个类似的“提交规则”语法，指示特定的异常将触发一次提交。<br>注
意上面示例的显式定位引用的方法只是一种访问受Spring管理BEAN的方法的变化，可以用在任何WEB资源如servlet或filter。在构建基
于Spring自身的MVC框架时，BEAN可以直接被注射到WEB控制器中。当然也支持在如Struts, WebWork, JSF, and
Tapestry框架中访问Spring管理BEAN。详情可以参考Spring的文档。<br><br><b><span style="font-size: 16px;">PlatformTransactionManager策略</span></b><br><br>Spring
事务支持的核心接口是org.springframework.transaction.PlatformTransactionManager。所有
Spring的事务分离功能都会委托给PlatformTransactionManager（传给相应的TransactionDefinition实
例）来做实际的事务执行。虽然PlatformTransactionManager接口可以直接调用，但通常应用只需要配置一个具体的事务管理器并且通
过声明性事务来分离事务。<br><br>Spring提供几种不同的PlatformTransactionManager实现，分为如下两个类别：<br>1、
本地事务策略—支持单一资源的事务（通常是单个数据库），其包括
org.springframework.jdbc.datasource.DataSourceTransactionManager和
org.springframework.orm.hibernate.HibernateTransactionManager。<br>2、全局事务管理—支持可能跨越多个资源的全局事务。其相应的类为org.springframework.transaction.jta.JtaTransactionManager，将事务委托给遵循JTA规范的事务协调器（通常为J2EE服务器，但不是强制的）。<br><br>PlatformTransactionManager
抽象的主要价值在于应用不再被绑定在特定的事务管理环境。相反，事务策略可以很容易地切换—通过选择不同的
PlatformTransactionManager实现类。这就使得应用代码与声明事务分离保持一致，而不需要考虑应用组件所使用的环境了。<br><br>例
如，应用的初始版本可能布署在Tomcat上，与单个Oracle数据库交互。这可以方便地利用Spring的事务分离特性，只要选择基于JDBC的
DataSourceTransactionManager作为使用的事务策略。Spring会分离事务，而JDBC驱动会执行相应的原始JDBC事务。<br><br>相
同应用的另一个版本可能会布署在WebLogic服务器上，使用两个Oracle数据库。应用代码和事务分离不需要改变。唯一不同的是选择作为
JtaTransactionManager事务策略，让Spring来分离事务而WebLogic服务器的事务协调器来执行事务。<br><br><b>JTA UserTransaction与JTA TransactionManager比较</b><br>让我们来看一下Spring对JTA支持的细节。虽然并非经常需要考虑这个细节但了解相关的细节还有必要的。对简单的用例如前面章节的示例，标准的JtaTransactionManager定义已经足够了，<br>缺
省的Spring
JtaTransactionManager设置会从标准JNDI位置（J2EE规范所定义的java:comp/UserTransaction）获取
JTA的javax.transaction.UserTransaction对象。这对大部分标准J2EE环境来说已经足够了。<br><br>然而，
缺省的JtaTransactionManager不能执行事务暂停（也就是说不支持PROPAGATION_REQUIRES_NEW和
PROPAGATION_NOT_SUPPORTED）。原因就在于标准的JTA
UserTransaction接口不支持事务的暂停和恢复，而只支持开始和完成新的事务。<br><br>为了实现事务的暂停，需要一个
javax.transaction.TransactionManager实例，他提供了JTA定义的标准的暂停和恢复方法。不幸的是，J2EE没有为
JTA TransactionManager定义标准的JNDI位置！因此，我们需要使用厂商自己的定位机制。<br><b>清单6：</b><br><pre title="pre code" class="overflow">&lt;bean id="transactionManager" <br>&nbsp;&nbsp; class="org.springframework.transaction.jta.JtaTransactionManager"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="transactionManagerName"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;vendorSpecificJndiLocation&lt;/value&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br>&lt;/bean&gt;</pre><br><br><br>J2EE
本质上没有考虑将JTA
TransactionManager接口作为公共API的一部分。JTA规范自身定义了将TransactionManager接口作为容器集成的想
法。虽然这是可以理解的，但是JTA
TransactionManager的标准JNDI位置还是可以增加一定的价值，特别是对轻量级容器如Spring,这样任何J2EE服务器就可以用统
一的方式来定位JTA TransactionManager了。<br><br>不仅Spring的JtaTransactionManager可以从
访问中获益，O/R映射工具如Hibernate, Apache OJB, and Kodo
JDO也能得到好处，因为他们需要在JTA环境中执行缓存同步的能力（释放缓存意味着JTA事务的完成）。这种注册事务同步的能力只有JTA
TransactionManager接口才能提供，而UserTransaction是处理不了的。因此，这些工具都需要实现自己的
TransactionManager定位器。<br><br>为JTA
TransactionManager定义标准的JNDI位置是许多底层软件供应商最期望J2EE实现的功能。如果J2EE5.0的规范制定团队能够认识
到这个特性的重要性就太好了。幸运地是，高级J2EE服务器如WebLogic Server已经考虑将JTA
TransactionManager作为公共的API包含在扩展功能中。<br><br><span style="font-size: 16px;"><b>在WebLogic JTA中实现Spring的事务分离</b></span><br>在WebLogic
Server中，JTA
TransactionManager官方的JNDI位置定义为javax.transaction.TransactionManager。这个值可以
在Spring的JtaTransactionManager中作为“transactionManagerName”使用。原则上这样就可以在
WebLogic's
JTA系统中实现事务暂停了，也就是说支持PROPAGATION_REQUIRES_NEW和PROPAGATION_NOT_SUPPORTED行
为。<br><br>除了标准的JtaTransactionManager和其支持的通用配置选项外，Spring还提供了一个专用的WebLogicJtaTransactionManager适配器来直接利用WebLogic的JTA扩展。<br><br>在享受自动探测WebLogic的JTA TransactionManager的便利之外，他提供超越标准JTA的三个重要特性：<br>1、事务命名—暴露出Spring的事务名给WebLogic Server，使得Spring事务在WebLogic的事务监听器可见。缺省的，Spring会使用声明性事务的完整方法名。<br>2、每事务隔离级别—将Spring事务属性中定义的隔离级别应用到WebLogic JTA事务中。这使得每个事务都可以定义数据库的隔离级别，而这是标准JTA所不支持的。<br>3、强制事务恢复—即使在暂停的事务被标识为回滚时也可以恢复。这需要使用WebLogic的扩展TransactionManager接口来调用forceResume()方法。<br> <br><img src="http://www.matrix.org.cn/resource/upload/forum/2005_12_16_002258_JYlbkfxrnW.gif" alt="image" style="display: inline;" onmouseover="javascript:ImgShowTip(this);" onload="javascript:ImgLoad(this);" onclick="javascript:ImgClick(this);" border="0" width="600"><br>Figure 2. WebLogic Server's transaction monitor (click the image for a full-size screen shot)<br><br>Spring的WebLogicJtaTransactionManager有效地为基于Spring的应用提供了WebLogic Server事务管理的全部功能。这使得Spring事务分离成为一种能与EJB CMT竟争的产品，而且提供了相同级别的事务支持。<br><br><b><span style="font-size: 16px;">Spring and EJB CMT</span></b><br><br>如
上所示，Spring的POJO声明性事务分离可以作为一种除传统EJB
CMT这外的选择。但是Spring与EJB并不是完成互斥的，Spring的应用上下文也可以作为EJB
fa&amp;ccedil;ade的后台来管理数据访问（DAO）和其他细纹理的业务对象。<br><br>在EJB情景中，事务是由EJB
CMT来驱动的。对Spring来说，数据访问支持特性会自动检测到这样的环境并且采用相应的事务。例如，Spring对Hibernate的支持能够提
供隐式的资源管理，即使是EJB驱动的事务，甚至可以在不需要修改任何DAO代码的情况下提供相同的语义。<br>Spring有效的解耦了DAO实现与实际的运行环境。DAO可以参与Spring的事务就像参与EJB CMT事务一样。这不仅简化在其他环境中的重用，而且更方便在J2EE容器外进行测试。<br><br><b><span style="font-size: 16px;">结论</span></b><br>Spring框架为J2EE和非J2EE环境提供了全量的事务分离的特性，特别表现在POJO的声明性事务上。他用一种灵活而非侵入式的方式为非EJB环境中的事务分离提供了便利。与EJB不同，这样的事务性POJO应用对象可以很容易的被测试和在J2EE容器外补重用。<br><br>Spring
提供了各种事务策略，如JtaTransactionManager是用来代理J2EE服务器的事务协调器，而JDBC
DataSourceTransactionManager是用来为简单的JDBC
DataSource（就是单一目标数据库）执行事务。Spring可以很容易为不同的环境通过后台配置的简单修改来调整事务策略。<br><br>超越
标准的JTA支持，Spring为WebLogic
Server的JTA扩展提供了完善的集成，可以支持高级特性如事务监视和每事务隔离级别。通过对WebLogic
Server的特殊支持，基于Spring的应用可以完全利用WebLogic Server的事务管理功能。<br><br>Spring事务分离是继
EJB
CMT之外的另一种可选方式，特别是对那些基于POJO的轻量级架构。在那只是因为选择LSSB（本地无状态会话BEAN）来应用声明性事务的情况下，基
于Spring的POJO服务模型是一种可行的选择，他提供了非常高层的灵活性、可测试性和重用性。<br><br><b><span style="font-size: 16px;">资源</span></b><br>&amp;#8226;<a href="http://java.sun.com/products/jta" target="_new">JTA - The JTA specification JTA规范</a><br>&amp;#8226;<a href="http://e-docs.bea.com/wls/docs81/jta/jtaapi.html#1053904" target="_new">WebLogic JTA - Documentation of WebLogic's JTA extensions WebLogic&nbsp;&nbsp;JTA扩展文档</a><br><br><b><span style="font-size: 16px;">关于作者</span></b><br>Juergen Hoeller是Spring框架的创始人之一<img src ="http://www.blogjava.net/ericwang/aggbug/24299.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ericwang/" target="_blank">Dion</a> 2005-12-16 22:39 <a href="http://www.blogjava.net/ericwang/archive/2005/12/16/24299.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转载】Spring中使用Annotation同时标记JMS+数据库事务</title><link>http://www.blogjava.net/ericwang/archive/2005/12/13/23751.html</link><dc:creator>Dion</dc:creator><author>Dion</author><pubDate>Tue, 13 Dec 2005 15:49:00 GMT</pubDate><guid>http://www.blogjava.net/ericwang/archive/2005/12/13/23751.html</guid><wfw:comment>http://www.blogjava.net/ericwang/comments/23751.html</wfw:comment><comments>http://www.blogjava.net/ericwang/archive/2005/12/13/23751.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ericwang/comments/commentRss/23751.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ericwang/services/trackbacks/23751.html</trackback:ping><description><![CDATA[<div class="postTitle">
		<a id="viewpost1_TitleUrl" class="postTitle2" href="http://steeven.cnblogs.com/archive/2005/11/17/278462.html">[java]Spring中使用Annotation同时标记JMS+数据库事务</a>
	</div>
	<p>对spring
了解的不够精通，这两天在解决jms异常的过程中发现，spring中提供了jmsTrasactionManager，同样实现了事务管理接口。这样用
自动的拦截器，就可以象数据库一样自动控制事务。在同时配置了JMS和数据库事务的时候，两者同时有效。这样系统的消息和数据库事务就轻量级的一致了！<br><br>数据库的spring配置参见：<a href="http://steeven.cnblogs.com/archive/2005/06/14/174410.html">http://steeven.cnblogs.com/archive/2005/06/14/174410.html</a><br>jms部分如下：<br></p>
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean&nbsp;</span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="remoteJmsConnectionFactory"</span><span style="color: rgb(255, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class</span><span style="color: rgb(0, 0, 255);">="org.activemq.ActiveMQConnectionFactory"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property&nbsp;</span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="useEmbeddedBroker"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">true</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property&nbsp;</span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="brokerURL"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">tcp://localhost:61616</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean&nbsp;</span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="jmsTM"</span><span style="color: rgb(255, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class</span><span style="color: rgb(0, 0, 255);">="org.springframework.jms.connection.JmsTransactionManager"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property&nbsp;</span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="connectionFactory"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">ref&nbsp;</span><span style="color: rgb(255, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">="remoteJmsConnectionFactory"</span><span style="color: rgb(255, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean&nbsp;</span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="jmsTransactionInterceptor"</span><span style="color: rgb(255, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class</span><span style="color: rgb(0, 0, 255);">="org.springframework.transaction.interceptor.TransactionInterceptor"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property&nbsp;</span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="transactionManager"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">ref&nbsp;</span><span style="color: rgb(255, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">="jmsTM"</span><span style="color: rgb(255, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property&nbsp;</span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="transactionAttributeSource"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean<br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(255, 0, 0);">class</span><span style="color: rgb(0, 0, 255);">="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"</span><span style="color: rgb(255, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean<br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(255, 0, 0);">class</span><span style="color: rgb(0, 0, 255);">="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property&nbsp;</span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="transactionInterceptor"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">ref&nbsp;</span><span style="color: rgb(255, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">="jmsTransactionInterceptor"</span><span style="color: rgb(255, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean&nbsp;</span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="destResolver"</span><span style="color: rgb(255, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class</span><span style="color: rgb(0, 0, 255);">="test.message.EnumDestinationResolver"</span><span style="color: rgb(255, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 128, 0);">&lt;!--</span><span style="color: rgb(0, 128, 0);">&nbsp;for&nbsp;send&nbsp;jms&nbsp;to&nbsp;remote&nbsp;server&nbsp;</span><span style="color: rgb(0, 128, 0);">--&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean&nbsp;</span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="remoteJmsTemplate"</span><span style="color: rgb(255, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class</span><span style="color: rgb(0, 0, 255);">="org.springframework.jms.core.JmsTemplate"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property&nbsp;</span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="connectionFactory"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">ref&nbsp;</span><span style="color: rgb(255, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">="remoteJmsConnectionFactory"</span><span style="color: rgb(255, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property&nbsp;</span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="destinationResolver"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">ref&nbsp;</span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="destResolver"</span><span style="color: rgb(255, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"></span></div><br>应用程序很简单<br><span style="color: rgb(0, 0, 0);">@Transactional<br><img id="Codehighlighter1_67_282_Open_Image" onclick="this.style.display='none'; Codehighlighter1_67_282_Open_Text.style.display='none'; Codehighlighter1_67_282_Closed_Image.style.display='inline'; Codehighlighter1_67_282_Closed_Text.style.display='inline';" src="http://steeven.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_67_282_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_67_282_Closed_Text.style.display='none'; Codehighlighter1_67_282_Open_Image.style.display='inline'; Codehighlighter1_67_282_Open_Text.style.display='inline';" src="http://steeven.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">&nbsp;TestServiceImpl&nbsp;implements&nbsp;TestService&nbsp;</span><span id="Codehighlighter1_67_282_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="http://steeven.cnblogs.com/Images/dot.gif"></span><span id="Codehighlighter1_67_282_Open_Text"><span style="color: rgb(0, 0, 0);">{<br><img id="Codehighlighter1_101_280_Open_Image" onclick="this.style.display='none'; Codehighlighter1_101_280_Open_Text.style.display='none'; Codehighlighter1_101_280_Closed_Image.style.display='inline'; Codehighlighter1_101_280_Closed_Text.style.display='inline';" src="http://steeven.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img id="Codehighlighter1_101_280_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_101_280_Closed_Text.style.display='none'; Codehighlighter1_101_280_Open_Image.style.display='inline'; Codehighlighter1_101_280_Open_Text.style.display='inline';" src="http://steeven.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">&nbsp;someMethod()&nbsp;</span><span id="Codehighlighter1_101_280_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="http://steeven.cnblogs.com/Images/dot.gif"></span><span id="Codehighlighter1_101_280_Open_Text"><span style="color: rgb(0, 0, 0);">{<br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getJmsTemplate().send(someMessage);<br></span><span style="color: rgb(0, 0, 0);"><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: rgb(0, 0, 0);"><br><img src="http://steeven.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">}<br></span></span><img src ="http://www.blogjava.net/ericwang/aggbug/23751.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ericwang/" target="_blank">Dion</a> 2005-12-13 23:49 <a href="http://www.blogjava.net/ericwang/archive/2005/12/13/23751.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转载】hibernate3.0+ejb3 annotaion配置实战+spring1.21 annotation事务控制</title><link>http://www.blogjava.net/ericwang/archive/2005/12/13/23747.html</link><dc:creator>Dion</dc:creator><author>Dion</author><pubDate>Tue, 13 Dec 2005 15:32:00 GMT</pubDate><guid>http://www.blogjava.net/ericwang/archive/2005/12/13/23747.html</guid><wfw:comment>http://www.blogjava.net/ericwang/comments/23747.html</wfw:comment><comments>http://www.blogjava.net/ericwang/archive/2005/12/13/23747.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/ericwang/comments/commentRss/23747.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ericwang/services/trackbacks/23747.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: hibernate3.0+ejb3 annotaion配置实战+spring1.21 annotation事务控制		我是比较讨厌xml的人，没有强类型，很多配置出错，包括xdoclet都无法检查。刚好现在的主流框架总算开始支持annotation了，所以玩了一下配置，供参考：hibernate3.05hibernate-annotations-3.0beta2spring1.21几个配置...&nbsp;&nbsp;<a href='http://www.blogjava.net/ericwang/archive/2005/12/13/23747.html'>阅读全文</a><img src ="http://www.blogjava.net/ericwang/aggbug/23747.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ericwang/" target="_blank">Dion</a> 2005-12-13 23:32 <a href="http://www.blogjava.net/ericwang/archive/2005/12/13/23747.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>扩展 Spring 的 JMX 支持</title><link>http://www.blogjava.net/ericwang/archive/2005/12/09/23230.html</link><dc:creator>Dion</dc:creator><author>Dion</author><pubDate>Fri, 09 Dec 2005 15:23:00 GMT</pubDate><guid>http://www.blogjava.net/ericwang/archive/2005/12/09/23230.html</guid><wfw:comment>http://www.blogjava.net/ericwang/comments/23230.html</wfw:comment><comments>http://www.blogjava.net/ericwang/archive/2005/12/09/23230.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ericwang/comments/commentRss/23230.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ericwang/services/trackbacks/23230.html</trackback:ping><description><![CDATA[<table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr valign="top"><td width="100%"><h1>扩展 Spring 的 JMX 支持</h1><p id="subtitle"><em>用 Spring 框架定制资源管理</em></p><img class="display-img" src="http://www.ibm.com/i/c.gif" alt="" height="6" width="1"></td><td class="no-print" width="192"><img src="http://www-128.ibm.com/developerworks/cn/i/dw.gif" alt="developerWorks" height="18" width="192"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr valign="top"><td width="10"><img src="http://www.ibm.com/i/c.gif" alt="" height="1" width="10"></td><td width="100%"><table class="no-print" align="right" border="0" cellpadding="0" cellspacing="0" width="160"><tbody><tr><td width="10"><img src="http://www.ibm.com/i/c.gif" alt="" height="1" width="10"></td><td><table border="0" cellpadding="0" cellspacing="0" width="150"><tbody><tr><td class="v14-header-1-small">文档选项</td></tr></tbody></table><table class="v14-gray-table-border" border="0" cellpadding="0" cellspacing="0"><tbody><tr><td class="no-padding" width="150"><img src="http://www.ibm.com/i/c.gif" alt="" height="1" width="8"><input name="body" value="Spring 框架将体系结构依赖性降至最低，并且将应用程序中的组成部分进行了具体化，但是应用程序仍然是需要管理的。幸运的是，Spring 1.2 包括高级的 JMX 集成支持 —— 并且 JMX 为应用程序提供了一种实用的管理基础架构。在本文中，Claude Duguay 从 Spring JMX 更进一步，向您展示了如何为方法和属性透明地增加通知事件。最后得到的代码使您可以监视状态变化，同时不会搞乱 Java 对象。" type="hidden"><input value="扩展 Spring 的 JMX 支持" name="subject" type="hidden"><input value="cn" name="lang" type="hidden"><table border="0" cellpadding="0" cellspacing="0" width="143"><form name="email" action="https://www-130.ibm.com/developerworks/secure/email-it.jsp"></form><script language="JavaScript" type="text/javascript">
<!--
document.write('<tr valign="top"><td width="8"><img src="//www.ibm.com/i/c.gif" width="8" height="1" alt=""/></td><td width="16"><img src="//www.ibm.com/i/v14/icons/em.gif" height="16" width="16" vspace="3" alt="将此页作为电子邮件发送" /></td><td width="122"><p><a class="smallplainlink" href="javascript:document.email.submit();"><b>将此页作为电子邮件发送</b></a></p></td></tr>');
//-->
</script><tbody><tr valign="top"><td width="8"><img src="http://www.ibm.com/i/c.gif" alt="" height="1" width="8"></td><td width="16"><img src="http://www.ibm.com/i/v14/icons/em.gif" alt="将此页作为电子邮件发送" height="16" vspace="3" width="16"></td><td width="122"><p><a class="smallplainlink" href="javascript:document.email.submit();"><b>将此页作为电子邮件发送</b></a></p></td></tr><noscript><tr
valign="top"><td width="8"><img src="//www.ibm.com/i/c.gif" width="8"
height="1" alt="" /></td><td width="16"><img
src="//www.ibm.com/i/c.gif" height="16" width="16" alt="" /></td><td
width="122" class="small"><p><span class="ast">未显示需要 JavaScript
的文档选项</span></p></td></tr></noscript><tr valign="top"><td width="8"><img src="http://www.ibm.com/i/c.gif" alt="" height="1" width="8"></td><td width="16"><img src="http://www.ibm.com/i/v14/icons/fw_bold.gif" alt="" border="0" height="16" vspace="3" width="16"></td><td width="122"><p><a class="smallplainlink" href="javascript:void forumWindow()"><b>讨论</b></a></p></td></tr><tr valign="top"><td width="8"><img src="http://www.ibm.com/i/c.gif" alt="" height="1" width="8"></td><td width="16"><img src="http://www.ibm.com/i/v14/icons/dn.gif" alt="" border="0" height="16" vspace="3" width="16"></td><td width="122"><p><a class="smallplainlink" href="http://www-128.ibm.com/developerworks/cn/java/j-springjmx/#download"><b>样例代码</b></a></p></td></tr></tbody></table></td></tr></tbody></table><br><table border="0" cellpadding="0" cellspacing="0" width="150"><tbody><tr><td class="v14-header-1-small">对此页的评价</td></tr></tbody></table><table class="v14-gray-table-border" border="0" cellpadding="0" cellspacing="0"><tbody><tr><td class="no-padding" width="150"><table border="0" cellpadding="0" cellspacing="0" width="143"><tbody><tr valign="top"><td width="8"><img src="http://www.ibm.com/i/c.gif" alt="" height="1" width="8"></td><td><img src="http://www.ibm.com/i/v14/icons/d_bold.gif" alt="" border="0" height="16" vspace="3" width="16"></td><td width="125"><p><a class="smallplainlink" href="http://www-128.ibm.com/developerworks/cn/java/j-springjmx/#rate"><b>帮助我们改进这些内容</b></a></p></td></tr></tbody></table></td></tr></tbody></table><br></td></tr></tbody></table><p>级别: 中级</p><p><a href="http://www-128.ibm.com/developerworks/cn/java/j-springjmx/#author">Claude Duguay </a>, 高级 J2EE 架构师, Capital Stream Inc.<br></p><p>2005 年  11 月  24 日</p><blockquote>Spring
框架将体系结构依赖性降至最低，并且将应用程序中的组成部分进行了具体化，但是应用程序仍然是需要管理的。幸运的是，Spring 1.2 包括高级的
JMX 集成支持，并且 JMX 为应用程序提供了一种实用的管理基础架构。在本文中，Claude Duguay 从 Spring JMX
更进一步，向您展示了如何为方法和属性透明地增加通知事件。最后得到的代码使您可以监视状态变化，同时不会搞乱 Java™ 对象。</blockquote><p>虽
然 Spring 框架的 JMX 管理基础架构的默认配置已经很不错了，但是仍然有定制的余地，特别是涉及 Model MBean
提供的更高层功能时。在本文中，我使用了一种相对简单的操作 —— 为基于 Spring 的应用程序的方法和属性增加通知事件 —— 以帮助您熟悉对
Spring JMX 的定制。从头到尾完成我的例子后，您将可以根据自己应用程序的需要调整 Spring JMX 管理基础架构。</p><p>我首
先对 JMX API、Spring 框架和 Spring JMX 进行简单回顾，然后转入开发扩展。第一个扩展让我可以用一个外部 XML
格式配置 MBean 元数据，这个格式（像 Hibernate 映射文件）可以与 Java 对象一起存储在类路径中。我的第二个扩展为 <code>ModelMBean</code> 类增加一个简单的命名规范，以透明地配置定制的通知消息。在属性改变时或者调用了特定的方法之前或者之后触发新的通知消息。</p><p>文章的最后是一个基于 mockup 服务对象的实际例子，需要管理它的启动和停止方法和读写属性。我用一个专门为此设计的小型客户机/服务器应用程序测试了这个实现。应用服务器是一个标准 Java 5.0 <code>MBeanServer</code>，并补充了源自 MX4J 开放源码项目的 HTTP 适配器。关于文章源代码请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-springjmx/#download">下载</a>，而技术下载请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-springjmx/#resources">参考资料</a>。</p><p><a name="IDAXDUW"><span class="atitle">JMX 概述</span></a></p><p>Java Management Extensions（JMX）是管理和监视网络上的服务的、基于 Java 的标准。JMX API 的核心是受管 bean，即 <i>MBean</i>。MBean
为受管资源（如应用程序、服务和设备）提供了设施层。简而言之，MBean 提供了一种灵活的、基于适配器的体系结构，用于开放基于 Java
的（或者 Java 包装的）资源的属性和操作。开放后，就可以用浏览器和 HTTP 连接或者通过像 SMTP 或者 SOAP
这样的协议监视和管理这些资源。</p><p>编写和部署的 MBean 是通过 <code>MBeanServer</code> 接口开放的，以使不同的应用程序视图具有交互性。<code>MBeanServer</code> 
实例还可以结合到任意的联合关系中，构成更复杂的分布式环境。</p><p>JMX 标准提供了四种不同的 MBean：</p><ul><li><b>Standard MBean</b> 直接实现用于管理对象的方法，既可以通过实现一个由程序员定义的、类名以 “<code>MBean</code>” 结束的接口，也可以使用一个以一个类作为构造函数参数的 Standard MBean 实例，加上一个可选的接口类规范。这个接口可以开放用于管理的部分对象方法。<br><br></li><li><b>Dynamic MBean</b> 用属性访问器动态地访问属性，并用一个一般化的 <code>invoke()</code> 方法调用方法。可用的方法是在 <code>MBeanInfo</code> 接口中指定的。这种方式更灵活，但是不具有像 Standard MBean 那样的类型安全性。它极大地降低了耦合性，可管理的 POJO（纯粹的老式 Java 对象）不需要实现特定的接口。<br><br></li><li><b>Model MBean</b>
提供了一个改进的抽象层，并扩展了 Dynamic MBean 模型以进一步减少对给定实现的依赖性。这对于可能使用多个版本的 JVM
或者需要用松散耦合管理第三方类的情况会有帮助。Dynamic MBean 与 Model MBean 之间的主要区别是，在 Model
MBean 中有额外的元数据。<br><br></li><li><b>Open MBean</b> 是受限的 Model MBean，它限制类型为固定的一组类型，以得到最大的可移植性。通过限制数据类型，可以使用更多的适配器，并且像 SMTP 这样的技术可以更容易适应 Java 应用程序的管理。这种变体还指定了数组和表等标准结构以改进复合对象的管理。</li></ul><p>如
果要同时控制客户机和服务器，那么 Standard MBean
是最容易实现的一种变体。它们的优点是有类型，但是如果在更一般化的管理控制台环境中使用时会缺少一些灵活性。如果计划使用 Dynamic
MBean，那么您也可以更一步使用 Model MBean，在大多数情况下它会改善抽象层而几乎不会增加复杂性。Open MBean
是是可移植性最高的一种变体，如果需要开放复合对象，那么它是惟一的方法。不幸的是，在 Open MBean
中开放复合结构所需要的代码数量过多，只有在需要高级的商业管理解决方案时才合算。</p><p>JMX 还支持使用带过滤器和广播器的事件模型的通知。为此目的，Standard MBean 需要声明一个 <code>MBeanInfo</code> 元数据描述。
Standard MBean 实现通常在内部构造这些内容，开发人员不能直接看到它们。在本文后面，您会看到如何用 Model MBean 元数据的 XML 描述符格式和 Spring 的 JMX 支持进行实际上透明的配置。</p><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" width="16"><br></td><td align="right" valign="top"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-springjmx/#main"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br><br><p><a name="IDARFUW"><span class="atitle">Spring 提供帮助</span></a></p><p>像
J2EE 一样，Spring 框架在一个体系结构中提供了许多强大的 Java 开发功能。与 J2EE 不同的是，Spring
开放型的技术来源提供了范围广泛的选择，不再有依赖性的负担。例如，Spring
的对象关系映射工具可以复制 Enterprise
JavaBean 的行为，同时不会导致不灵活。虽然
EJB 规范限制了这种方式，但是 Spring
提供了大量技术接口，使您可以选择最适合应用程序要求的接口，或者在需要时创建自己的接口。与此类似，利用 Spring 的动态代理类为 Java
对象增加事务性或者安全限制，使它们保持整洁并针对应用程序空间而不是基础架构要求。</p><p>Spring 的支持 AOP 的、以复合为中心的（IOC）bean 可以很大程度上使基础架构和业务对象彼此分离。因此，横切关注点（如日志、事务和安全）不会再干扰应用程序代码。</p><p>IOC
（控制反转）是减少耦合度的主要策略。Spring 的 IOC 实现使用依赖性注入有效地将控制从应用程序代码
“反转”到 Spring 容器。Spring 不是在创建时将类耦合到应用程序的对象图，它使您可以用 XML 或者属性文件（尽管 XML
被认为是最好的方法）配置类及它们的依赖性。然后用标准访问器将引用“注入”到类所依赖的对象中。可以将它看成具体化复合（externalizing
composition），在典型应用程序中，它的比重远远大于继承。</p><p>AOP 是在应用程序开发中管理横切关注点的关键。就像在传统面向对象编程中实现的那样，这些关注点是作为单独的实例处理的，有可能在应用程序类中产生互不相关的代码（就是混乱）。
Spring 使用 AOP 规范和一个 XML 配置文件具体化横切关注点，因而保持了 Java 代码的纯洁性。</p><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" width="16"><br></td><td align="right" valign="top"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-springjmx/#main"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br><br><p><a name="IDA0FUW"><span class="atitle">介绍 Spring JMX</span></a></p><p>Spring 1.2 中的 JMX 支持使用容易配置的 bean 代理提供了自动 <code>MBeanServer</code> 注册，并支持标准 JSR-160 远程连接器。在最简单的情况下，可以用 Spring JMX 以 <code>MBeanExporter</code> 类注册对象。Spring 自动识别 <code>StandardMBean</code> 或者用 <code>ModelMBean</code> 代理包装对象，在默认情况下使用内省。可以以显式引用使用 <code>BeanExporter</code> 
以声明 bean，或者可以用默认策略或更复杂的策略自动检测 bean。</p><p>Spring
1.2 提供的大量装配器使得透明地构造 MBean 成为可能，包括使用内省、Standard MBean
接口、元数据（使用类级别注释）和显式声明的方法名。Spring 的基于导出器和装配器的模型容易扩展，并在创建注册的 MBean
时提供所需要的控制能力。</p><p>JMX 使用 <code>ObjectName</code> 语言注册和访问管理对象。如果选择使用自动注册，那么 Spring 提供了不同的命名策略。使用“键”命名策略时，可以使用一个属性把 MBean
名与 <code>NameObject</code> 实例关联起来。如果实现
<code>ManagedResource</code> 接口，那么可以使用元数据命名规范。由于 Spring 高度灵活的体系结构和大量扩展点，还可以实现自已的策略。</p><p>在默认情况下，Spring 会发现运行的 <code>MBeanServer</code> 实例，如果没有实例在运行或者没有显式声明的话，它会创建一个默认实例。用 Spring 配置直接实例化自己的 <code>MBeanServer</code> 与使用各种连接器同样容易。Spring 通过客户机和服务器连接提供控制，并提供客户机代理以协助客户端编程。</p><p>所
有这些功能都是 Spring
1.2 默认提供的。虽然 Spring JMX 提供了大量选项，但是默认的导出器对于许多项目来说已经足够了，使您可以很快地投入运行。不过，使用
JMX 时，在使用隐式 MBean 构造时会注意到一些特性。结果，可能会慢慢地从 Standard MBean 转移到 Model
MBean，它允许对应用程序的属性、操作和通知元数据施加更多的控制。要保留松散耦合的好处（也就是 Spring
灵活的体系结构内在的优点），需要在 Java 对象之外实现这个控制。</p><p>Spring
的 IOC 使得从外部连接（wire）对象依赖性容易了，在 Spring 的体系结构中很容易利用这种优点。IOC
保持对象依赖性的可注入性，这使得增加、替换或者补充对象的行为（包括 Spring 的 JMX
支持）变得轻而易举。在本文的其余部分，我将重点放到扩展 Spring JMX 以得到更细化的应用程序管理，而不会搞乱应用程序代码或者破坏
Spring 固有的灵活性。</p><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" width="16"><br></td><td align="right" valign="top"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-springjmx/#main"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br><br><p><a name="IDAQHUW"><span class="atitle">扩展 Spring JMX</span></a></p><p>Spring 框架提供了许多处理 JMX 的有用工具，包括用于扩展 JMX 功能的扩展点。我将利用它们获得对 <code>MBeanInfo</code>
声明的更多控制，同时不用对 Java 对象施加注释。为此，我将要以两种方式扩展 Spring JMX：第一种方法可以用一个外部 XML
格式（类似于 JBoss 微内核）配置 MBean 元数据，第二种方法可以与其相关联的 Java 对象一同存储在在类路径中（很像
Hibernate
映射文件）。</p><table align="right" border="0" cellpadding="0" cellspacing="0" width="40%"><tbody><tr><td width="10"><img src="http://www.ibm.com/i/c.gif" alt="" height="1" width="10"></td><td><table border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td bgcolor="#eeeeee"><a name="IDA4HUW"><b>推荐的文章</b></a><br><p>Spring 1.2 的文档有整整一章关于 JMX 的内容，如果想要在 Spring 中使用 JMX 就应该阅读它。有关 Spring 1.2 文档的内容请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-springjmx/#resources">参考资料</a>。</p></td></tr></tbody></table></td></tr></tbody></table><p>我将扩展 <code>RequiredModelMBean</code> 类，让它使用一个简单的命名规范，以 <code>&lt;ClassName&gt;.mbean.xml</code> 格式寻找相关的 MBean 部署描述符。定义这种基于 XML 的 <code>MBean</code> 描述符改进了对应用程序元数据的控制，而不会失去基于 POJO 的设计和 Spring 复合的灵活性。为了实现这一点，我将实现自己的装配器并扩展基本的 Spring JMX 导出器。扩展的导出器可以创建扩展的 <code>ModelMBean</code>，它支持截获属性的改变以及 <code>before</code> 和 <code>after</code> 方法执行的通知。我可以用 Spring 的 AOP 机制完成这一切，但是 <code>ModelMBean</code> 已经是底层受管资源的代理，因此我将用更直接的方式扩展
<code>RequiredModelMbean</code> 类。</p><p><a name="IDANB4W"><span class="smalltitle">管理基础</span></a></p><p>不管使用什么技术，在管理资源时有三个要关注的主要领域：</p><ul><li><b>属性（attribute）</b> （有时称为属性（property）、字段或者变量）。只读属性对于开放度量或者状态很有用。读/写属性使管理员可以改变配置。<br><br></li><li><b>动作（action）</b> （可执行调用，对于 Java 代码来说就是方法）。动作用于触发像启动和关闭这样的事件，或者其他特定于应用程序的操作。<br><br></li><li><b>事件（event）</b>
（向监视系统发出的通知，反映状态改变或者一些操作的执行）。通知确认操作或者状态改变确实发生了。通知还可以用于触发事件，如对于超过设置阀值（比如内
存或者磁盘空间等资源不足）的状态改变做出反应。这种通知可以用于在系统需要关注时向应用程序管理员发送电子邮件或者传呼。</li></ul><p>在
扩展 Spring JMX
时，我将用一个简单的案例分别展示这三个需要关注的领域：一个带有开始和停止方法并且有一个读写属性要管理的示例服务。我还要用一个小型的客户机/服务器
应用程序测试这个实现，并开放一个使用 MX4J 适配器的 HTTP
管理接口。所有例子将有必要的限制，但是足以使您理解相应的概念。您会看到在基于 Spring 的应用程序方法和属性中加入 JMX
通知事件有多么容易，结果是可以监视状态改变，同时不会在 Java 对象中加入不必要的代码。</p><p><a name="IDACC4W"><span class="smalltitle">MBeanInfo 模型</span></a></p><p>如果下载与本文有关的代码，您会发现一个名为 <code>com.claudeduguay.mbeans.model</code> 的包，它包含一组用于建模 <code>MBeanInfo</code> XML
文件的类。这个包包含大量类，因此我不会详细讨论所有类，但是其基本内容还是有必要说明的。</p><p>模型的根是 <code>MBeanDescriptor</code> 类，它提供了一个 <code>createMBeanInfo()</code> 方法，负责用应用程序元数据创建一个兼容
JMX 的 <code>ModelMBeanInfo</code> 实例。<code>MBeanDescriptorUtil</code> 类提供了两个静态的 <code>read()</code> 方法，它装载并保存这个 XML 文档模型。这个模型中使用的 <code>Document</code> 和 <code>Element</code> 实例基于 JDOM 框架。</p><p>我使用的基本 <code>MBeanInfo</code> 相关类和描述符模型是密切相关的。基类中的所有基本属性都是在 XML 中建模的，并可以用简单的格式定义。例如，<code>&lt;mbean&gt;</code> 标记是我的文档的根。它与 <code>ModelMBeanInfo</code> 直接相关，它期待一个 <i>type</i> 和 <i>description</i> 属性。类型是受管 bean 的完全限定类名。不过，在使用我的 Sping 解决方案时，这个类完全可以在上下文中派生。<code>&lt;mbean&gt;</code> 标记期待零个或者多个 <i>attribute</i>、<i>operation</i>、<i>constructor</i> 和 <i>notification</i> 子类型。它们每一个都提供了基 <code>MBeanInfo</code> 类 XML 属性。</p><br><a name="IDASE4W"><b>图 1. MBean XML 格式</b></a><br><img alt="图 1. MBean XML 格式" src="http://www-128.ibm.com/developerworks/cn/java/j-springjmx/MBeanXMLFormat.jpg"><br><p><code>MBean</code> 模型实现利用了 <code>com.claudeduguay.util.jdom</code> 包中几个与 JDOM 相关的工具类。它们主要是解析和构建 <code>Document</code> 和 <code>Element</code> 对象的接口，一个工具类使读和写 <code>Document</code> 流更容易。要查看的大多数代码在
<code>com.claudeduguay.mbeans.spring</code> 包中。</p><p>已经做了足够的预备工作，让我们开始扩展 Spring JMX!</p><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" width="16"><br></td><td align="right" valign="top"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-springjmx/#main"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br><br><p><a name="IDAVF4W"><span class="atitle">改进 ModelMBean 中的通知</span></a></p><p>我要做的第一件事是扩展 Spring JMX <code>ModelMBean</code> 实现，这样就可以发送通知而不用在管理的资源中直接实现这个行为。为此，还需要扩展 Spring 导出器以创建改进的 <code>ModelMBean</code> 实例。最后，还需要用一个新的装配器从映射文件中提取 <code>MBeanInfo</code> 元数据。</p><p><a name="IDAIG4W"><span class="smalltitle">ModelMBeanExtension 类</span></a></p><p>扩展 <code>RequiredModelMBean</code> 类的一个目的是在管理代理中透明地启用通知。这个应用程序需要三种通知：设置属性值、方法调用之前以及方法调用之后。因为消息是我自己配置的，在每一种情况下，它都可以按照我需要的那样提供信息。要实现这一点，我对类型通知使用了一个命名规范，其中对于样式 <code>&lt;matchingType&gt;.&lt;methodOrAttributeName&gt;</code> 检查点分隔的类型名。匹配的类型必须为 <code>set</code>、<code>before</code> 或者 <code>after</code> 之一。如果类型是 <code>set</code>，那么就认为是一个属性名，否则，就认为是一个方法名。</p><p>扩展的 <code>ModelMBean</code> 代码使用额外的类帮助进行耦合。第一个是
<code>NotificationInfoMap</code>，它是一个用通知元数据构建的、简单的 <code>Map</code>，并与前缀（<i>set|before|after</i>）点名（<i>method|attribute</i>）样式相关联，这样就可以更有效地得到匹配的通知元数据。第二个是工具方法的一个静态集合。清单 1 显示了为通知而扩展的 <code>RequiredModelMBean</code>：</p><br><a name="code1"><b>清单 1. ModelMBeanExtension</b></a><br><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><code class="section"><br>package com.claudeduguay.mbeans.spring;<br><br>import java.lang.reflect.*;<br><br>import javax.management.*;<br>import javax.management.modelmbean.*;<br><br>public class ModelMBeanExtension extends RequiredModelMBean<br>{<br>  protected NotificationInfoMap notificationInfoMap;<br>  protected ModelMBeanInfo modelMBeanInfo;<br>  protected Object managedBean;<br>  <br>  public ModelMBeanExtension() throws MBeanException {}<br><br>  public ModelMBeanExtension(ModelMBeanInfo modelMBeanInfo)<br>    throws MBeanException<br>  {<br>    super(modelMBeanInfo);<br>    this.modelMBeanInfo = modelMBeanInfo;<br>    notificationInfoMap = new NotificationInfoMap(modelMBeanInfo);<br>  }<br>  <br>  public void setModelMBeanInfo(ModelMBeanInfo modelMBeanInfo)<br>    throws MBeanException<br>  {<br>    this.modelMBeanInfo = modelMBeanInfo;<br>    notificationInfoMap = new NotificationInfoMap(modelMBeanInfo);<br>    super.setModelMBeanInfo(modelMBeanInfo);<br>  }<br>  <br>  public MBeanNotificationInfo[] getNotificationInfo()<br>  {<br>    return modelMBeanInfo.getNotifications();<br>  }<br>  <br>  public void setManagedResource(Object managedBean, String type)<br>    throws MBeanException, RuntimeOperationsException,<br>      InstanceNotFoundException, InvalidTargetObjectTypeException<br>  {<br>    super.setManagedResource(managedBean, type);<br>    this.managedBean = managedBean;<br>  }<br>  <br>  protected void maybeSendMethodNotification(<br>  	String type, String name) throws MBeanException<br>  {<br>    MBeanNotificationInfo info = notificationInfoMap.<br>      findNotificationInfo(type, name);<br>    if (info != null)<br>    {<br>      long timeStamp = System.currentTimeMillis();<br>      String notificationType = ModelMBeanUtil.<br>        matchType(info, "." + type + "." + name);<br>      sendNotification(new Notification(<br>        notificationType, this, timeStamp,<br>        info.getDescription()));<br>    }<br>  }<br><br>  protected void maybeSendAttributeNotification(<br>    Attribute attribute)<br>    throws MBeanException, AttributeNotFoundException,<br>    InvalidAttributeValueException, ReflectionException<br>  {<br>    String name = attribute.getName();<br>    MBeanNotificationInfo info = notificationInfoMap.<br>      findNotificationInfo("set", attribute.getName());<br>    if (info != null)<br>    {<br>      Object oldValue = getAttribute(name);<br>      Object newValue = attribute.getValue();<br>      long timeStamp = System.currentTimeMillis();<br>      String notificationType = ModelMBeanUtil.<br>        matchType(info, ".set." + name);<br>      sendNotification(new AttributeChangeNotification(<br>        this, timeStamp, timeStamp,<br>        info.getDescription(), info.getName(),<br>        notificationType, oldValue, newValue));<br>    }<br>  }<br>  <br>  public Object invoke(<br>  	String name, Object[] args, String[] signature)<br>      throws MBeanException, ReflectionException<br>  {<br>    maybeSendMethodNotification("before", name);<br>    Object returnValue = super.invoke(name, args, signature);<br>    maybeSendMethodNotification("after", name);<br>    return returnValue;<br>  }<br><br>  public Object getAttribute(String name) throws MBeanException,<br>    AttributeNotFoundException, ReflectionException<br>  {<br>    try<br>    {<br>      Method method = ModelMBeanUtil.findGetMethod(<br>        modelMBeanInfo, managedBean, name);<br>      return method.invoke(managedBean, new Object[] {});<br>    }<br>    catch (IllegalAccessException e)<br>    {<br>      throw new MBeanException(e);<br>    }<br>    catch (InvocationTargetException e)<br>    {<br>      throw new MBeanException(e);<br>    }<br>  }<br><br>  public void setAttribute(Attribute attribute)<br>    throws MBeanException, AttributeNotFoundException,<br>      InvalidAttributeValueException, ReflectionException<br>  {<br>    try<br>    {<br>      Method method = ModelMBeanUtil.findSetMethod(<br>        modelMBeanInfo, managedBean, attribute.getName());<br>      method.invoke(managedBean, attribute.getValue());<br>      maybeSendAttributeNotification(attribute);<br>    }<br>    catch (InvocationTargetException e)<br>    {<br>      throw new MBeanException(e);<br>    }<br>    catch (IllegalAccessException e)<br>    {<br>      throw new MBeanException(e);<br>    }<br>  }<br>}<br></code></pre></td></tr></tbody></table><br><p><a name="IDAII4W"><span class="smalltitle">不需要代理代理！</span></a></p><p>因为 <code>ModelMBean</code> 已经是一种代理，所以不需要使用 Spring 的代理机制和 AOP
截获器来截获感兴趣的方法。<code>ModelMBean</code> 接口需要 <code>setAttribute</code> 和 <code>invoke</code> 方法的实现以管理对底层受管资源的调用。可以继承 <code>RequiredModelMBean</code> 类，保证它出现在所有 JMX 实现中，并增加我所需要的功能。</p><p>我的 <code>ModelMBeanExtension</code> 实现了同样的构造函数，但是在一个实例变量中存储了 <code>ModelMBeanInfo</code> 的一个副本。因为这个值可以通过构造函数或者调用 <code>setModelMBeanInfo</code> 方法设置，所以我覆盖了这个方法以存储这个值，调用超类以完成默认的行为。在默认情况下，<code>RequiredModelMBean</code> 类增加两个一般性通知描述符，因此我覆盖了 <code>getNotificationInfo()</code> 方法，只返回我描述的通知。仍然会发送一般性通知，但是要求特定通知的客户不会看到它们。</p><p>为了发送通知，我覆盖了 <code>setAttribute()</code> 和 <code>invoke()</code> 方法并检查调用是否匹配我的通知信息描述符。每次都遍历列表应该不会带来很大的开销，因为大多数类只会发送有限的一组通知，但是我需要测试每一个通知可能的许多通知类型字符串，而重复这一过程看来是个浪费。为了保证不会遇到性能问题，我实例化了一个<i>通知信息映射</i>，这是一个名称/信息映射，可以用来进行快速查询。关键是一个具有类型前缀（<code>set</code>、<code>before</code> 或者 <code>after</code>）和所涉及的属性和方法的简单字符串。可以使用 <code>findNotificationInfo()</code> 方法在 <code>setAttribute()</code> 调用或者方法调用时查找通知信息实例。</p><p>完成了基础架构后，就可以截获对 <code>setAttribute()</code> 和 <code>invoke()</code> 方法的调用了。属性改变需要发送一个 <code>AttributeChangeNotification</code> 实例，它要求有旧的属性值和新的值，以及从通知信息描述符中可以得到的细节。在发送通知时，如果消息顺序是混乱的，则要发送序列号，让客户机应用程序可以对消息排序。为了简化，我使用了当前时间戳而不是管理一个计数器。创建通知对象时，<code>sendNotification()</code> 方法保证它会发布。对于 <code>invoke()</code>
  方法使用同样的思路，尽管在这里我使用了更简单的 <code>Notification</code> 对象。可以调用超类中的 <code>invoke()</code> 方法同时检查这两者（<code>before</code> 和 <code>after</code>），并根据查找结果发送 <code>before</code> 和 <code>after</code> 通知。</p><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" width="16"><br></td><td align="right" valign="top"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-springjmx/#main"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br><br><p><a name="IDAHM4W"><span class="atitle">扩展 Spring JMX 导出器</span></a></p><p>为了使用扩展的 <code>ModelMBean</code>，需要覆盖 Spring <code>MBeanExporter</code> 中的 <code>createModelMBean()</code> 方法。因为可以注入装配器属性，所以必须知道它可能不是我所期待的这一事实。可以在构造函数中设置所需要的装配器，但是当装配器改变时需要返回一个普通 <code>ModelMBean</code>。所要做的就是缓存一个 <code>MBeanInfoAssembler</code> 的本地引用，并在创建新的 <code>ModelMBean</code> 时检查它是什么类型的。清单 2 显示了所有这些改变：</p><br><a name="code2"><b>清单 2. MBeanDescriptorEnabledExporter</b></a><br><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><code class="section"><br>package com.claudeduguay.mbeans.spring;<br><br>import javax.management.*;<br>import javax.management.modelmbean.*;<br><br>import org.springframework.jmx.export.*;<br>import org.springframework.jmx.export.assembler.*;<br><br>public class MBeanDescriptorEnabledExporter extends MBeanExporter<br>{<br>  protected MBeanInfoAssembler mBeanInfoAssembler;<br>  <br>  public MBeanDescriptorEnabledExporter()<br>  {<br>    setAssembler(new MBeanDescriptorBasedAssembler());<br>  }<br>  <br>  public ModelMBean createModelMBean() throws MBeanException<br>  {<br>    if (mBeanInfoAssembler instanceof MBeanDescriptorBasedAssembler)<br>    {<br>      return new ModelMBeanExtension();<br>    }<br>    return super.createModelMBean();<br>  }<br>  <br>  public void setAssembler(MBeanInfoAssembler mBeanInfoAssembler)<br>  {<br>    this.mBeanInfoAssembler = mBeanInfoAssembler;<br>    super.setAssembler(mBeanInfoAssembler);<br>  }<br>}<br></code></pre></td></tr></tbody></table><br><p>在使用这个扩展的类时，可以用标准 Spring 语言改变装配器，并在需要时回到默认的行为。在大多数情况下，如果最终绕过扩展，那么就不值得使用这个版本。不过，如果想要以新的定制装配器使用扩展的 <code>ModelMBean</code>，那么现在可以这样做。</p><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" width="16"><br></td><td align="right" valign="top"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-springjmx/#main"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br><br><p><a name="IDAUN4W"><span class="atitle">构建一个定制的装配器</span></a></p><p>这个定制装配器的主要任务是查找与管理的类有关的元数据映射文件。找到这个文件后，就装载它并生成必要的 <code>ModelMBeanInfo</code> 实例。为此，我只是实现了 Spring <code>MBeanInfoAssembler</code> 实例建立这个文件的相关类路径，用静态
<i>MBeanDescriptorUtil.read()</i> 方法装载它并返回结果，如清单 3 所示：</p><br><a name="code3"><b>清单 3. MBeanDescriptorBasedAssembler</b></a><br><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><code class="section"><br>package com.claudeduguay.mbeans.spring;<br><br>import java.io.*;<br><br>import javax.management.modelmbean.*;<br><br>import org.springframework.core.io.*;<br>import org.springframework.jmx.export.assembler.*;<br><br>import com.claudeduguay.mbeans.model.*;<br><br>public class MBeanDescriptorBasedAssembler<br>  implements MBeanInfoAssembler<br>{<br>  public ModelMBeanInfo getMBeanInfo(<br>    Object managedBean, String beanKey)<br>  {<br>    String name = managedBean.getClass().getName();<br>    String path = name.replace('.', '/') + ".mbean.xml";<br>    <br>    ClassPathResource resource = new ClassPathResource(path);<br>    InputStream input = null;<br>    try<br>    {<br>      input = resource.getInputStream();<br>      MBeanDescriptor descriptor = MBeanDescriptorUtil.read(input);<br>      return descriptor.createMBeanInfo();<br>    }<br>    catch (Exception e)<br>    {<br>      throw new IllegalStateException(<br>        "Unable to load resource: " + path);<br>    }<br>    finally<br>    {<br>      if (input != null)<br>      {<br>        try { input.close(); } catch (Exception x) {}<br>      }<br>    }<br>  }<br>}<br></code></pre></td></tr></tbody></table><br><p>这个 <code>MBeanDescriptorBasedAssembler</code> 忽略 bean 键参数并直接用受管 bean 引用创建所需的 <code>ModelMBeanInfo</code> 实例。</p><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" width="16"><br></td><td align="right" valign="top"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-springjmx/#main"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br><br><p><a name="IDAXO4W"><span class="atitle">示例</span></a></p><p>在本文其余部分，我将着重展示这个 Spring JMX 扩展的使用。为此，使用一个假想的服务，它开放两个方法和一个属性，因此表现了典型的用例。</p><p><code>ExampleService</code> 是一个 Java 对象，它在被调用时只是向控制台进行输出，如清单 4 所示：</p><br><a name="code4"><b>清单 4. ExampleService</b></a><br><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><code class="section"><br>package com.claudeduguay.jmx.demo.server;<br><br>public class ExampleService<br>{<br>  protected String propertyValue = "default value";<br>  <br>  public ExampleService() {}<br>  <br>  public String getPropertyValue()<br>  {<br>    System.out.println("ExampleService: Get Property Value");<br>    return propertyValue;<br>  }<br><br>  public void setPropertyValue(String propertyValue)<br>  {<br>    System.out.println("ExampleService: Set Property Value");<br>    this.propertyValue = propertyValue;<br>  }<br><br>  public void startService()<br>  {<br>    System.out.println("ExampleService: Start Service Called");<br>  }<br><br>  public void stopService()<br>  {<br>    System.out.println("ExampleService: Stop Service Called");<br>  }<br>}<br></code></pre></td></tr></tbody></table><br><p><a name="IDAKP4W"><span class="smalltitle">对管理员友好的消息</span></a></p><p>这个扩展的描述符可以几乎直接关联属性和操作。描述符方法优于内省式方法的主要一点是可以提供更特定的消息。通知描述符的配置选项有赖于类型（XML）属性的命名规范。实际的名字是任意的，但是代码会被类型中的 <code>set.name</code>、<code>before.name</code> 和 <code>after.name</code> 样式触发。在这种情况下，我将 <code>set</code> 通知与 <code>propertyValue</code> （JMX）属性关联，将 <code>before</code> 与 <code>after</code> 通知与 <code>startService()</code> 与 <code>stopService()</code> 方法关联。同样，这些扩展使我可以很好利用描述性的消息。</p><p>在清单 5 中，可以看到定义了一个属性和两个方法。通知描述符定义了方法的之前和之后事件以及一个属性设置通知：</p><br><a name="code5"><b>清单 5. ExampleService.mbean.xml</b></a><br><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><code class="section"><br>&lt;?xml version="1.0"?&gt;<br>&lt;mbean name="ExampleService" description="Example Service"<br>  type="com.claudeduguay.jmx.demo.server.ExampleService"&gt;<br><br>  &lt;attribute name="propertyValue"<br>    description="Property Value Access" type="java.lang.String"<br>    readable="true" writable="true" /&gt;<br><br>  &lt;operation name="stopService"<br>    description="Stop Example Service" /&gt;<br>  &lt;operation name="startService"<br>    description="Start Example Service" /&gt;<br><br>  &lt;notification name="PropertyValueSet"<br>    types="example.service.set.propertyValue"<br>    description="PropertyValue was set" /&gt;<br>  &lt;notification name="BeforeStartService"<br>    types="example.service.before.startService"<br>    description="Example Service is Starting" /&gt;<br>  &lt;notification name="AfterStartService"<br>    types="example.service.after.startService"<br>    description="Example Service is Started" /&gt;<br>  &lt;notification name="BeforeStopService"<br>    types="example.service.before.stopService"<br>    description="Example Service is Stopping" /&gt;<br>  &lt;notification name="AfterStopService"<br>    types="example.service.after.stopService"<br>    description="Example Service is Stopped" /&gt;<br>  <br>&lt;/mbean&gt;<br></code></pre></td></tr></tbody></table><br><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" width="16"><br></td><td align="right" valign="top"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-springjmx/#main"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br><br><p><a name="IDABR4W"><span class="atitle">配置服务器</span></a></p><p>要在客户机/服务器环境中运行这个例子，需要配置和启动一个 <code>MBeanServer</code> 实例。为此，我使用 Java 5.0 <code>MBeanServer</code> 实例，它保证我可以使用 JVM 中提供的管理扩展，同时管理自己的代码。如果愿意，还可以运行 <code>MBeanServer</code> 的多个实例，您愿意的话也可以自己试一试作为练习。</p><p>就像 Java 5.0 一样，Spring 框架使您可以配置自己的 <code>MBeanServer</code> 实例。我选择使用 Java 5.0，因为它支持 JSR-160 连接器，我的客户机代码会需要它。</p><br><a name="code6"><b>清单 6. SpringJmxServer</b></a><br><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><code class="section"><br>package com.claudeduguay.jmx.demo.server;<br><br>import org.springframework.context.*;<br>import org.springframework.context.support.*;<br><br>import mx4j.tools.adaptor.http.*;<br><br>/*<br> * To use the SpringJmxServer, use the following command line<br> * arguments to activate the Java 1.5 JMX Server.<br> * <br> * -Dcom.sun.management.jmxremote.port=8999<br> * -Dcom.sun.management.jmxremote.ssl=false<br> * -Dcom.sun.management.jmxremote.authenticate=false<br> */<br><br>public class SpringJmxServer<br>{<br>  public static void main(String[] args)<br>    throws Exception<br>  {<br>    String SPRING_FILE =<br>      "com/claudeduguay/jmx/demo/server/SpringJmxServer.xml";<br>    ApplicationContext context =<br>      new ClassPathXmlApplicationContext(SPRING_FILE);<br>    HttpAdaptor httpAdaptor =<br>      (HttpAdaptor)context.getBean("HttpAdaptor");<br>    httpAdaptor.start();<br>  }<br>}<br></code></pre></td></tr></tbody></table><br><p>由于有了 <code>MBeanDescriptorEnabledExporter</code>，服务器的 Spring 配置文件非常简单。除了声明 <code>ExampleService</code>，我增加了开放一个 HTTP 适配器和连接
<code>XSLTProcessor</code> 到 <code>HttpAdaptor</code> 所需要的 MX4J 项。注意这是 Spring 的 IOC 实现非常有用的一个领域。清单 7 显示了我的
 <code>SpringJmxServer</code> 实例的 Spring 配置文件：</p><br><a name="code7"><b>清单 7. SpringJmxServer.xml</b></a><br><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><code class="section"><br>&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br>&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"<br>  "http://www.springframework.org/dtd/spring-beans.dtd"&gt;<br>&lt;beans&gt;<br>  &lt;bean id="exporter" class=<br>    "com.claudeduguay.mbeans.spring.MBeanDescriptorEnabledExporter"&gt;<br>    &lt;property name="beans"&gt;<br>      &lt;map&gt;<br>        &lt;entry key="Services:name=ExampleService"<br>          value-ref="ExampleService" /&gt;<br>        &lt;entry key="MX4J:name=HttpAdaptor"<br>          value-ref="HttpAdaptor" /&gt;<br>        &lt;entry key="MX4J:name=XSLTProcessor"<br>          value-ref="XSLTProcessor" /&gt;<br>      &lt;/map&gt;<br>    &lt;/property&gt;<br>  &lt;/bean&gt;<br>  <br>  &lt;bean id="XSLTProcessor"<br>    class="mx4j.tools.adaptor.http.XSLTProcessor" /&gt;<br>  &lt;bean id="HttpAdaptor"<br>    class="mx4j.tools.adaptor.http.HttpAdaptor"&gt;<br>    &lt;property name="processor" ref="XSLTProcessor"/&gt;<br>    &lt;property name="port" value="8080"/&gt;<br>  &lt;/bean&gt;<br>  <br>  &lt;bean id="ExampleService"<br>    class="com.claudeduguay.jmx.demo.server.ExampleService" /&gt;<br><br>&lt;/beans&gt;<br></code></pre></td></tr></tbody></table><br><p>如果愿意（假定您遵循了我的设置），那么现在就可以运行这个服务器了。它会注册 <code>ExampleService</code> 并运行 HTTP 适配器。不要忘记使用注释中提到的命令行参数启动 Java 5.0 <code>MBeanServer</code>，否则会得到默认实例，客户机示例就不能工作了。</p><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" width="16"><br></td><td align="right" valign="top"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-springjmx/#main"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br><br><p><a name="IDAKT4W"><span class="atitle">运行客户机代码</span></a></p><p>启动服务器后，可以运行如清单 8 所示的客户机代码看看会发生什么。这段代码实现了 JMX <code>NotificationListener</code> 接口，这样就可以交互式地看到所发生的事情。连接后，可以注册监听器，然后触发几个调用、启动和停止服务、设置和取得属性。在每一种情况下，都应当在控制台上看到一个确认操作的通知消息。</p><br><a name="code8"><b>清单 8. SpringJmxClient</b></a><br><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><code class="section"><br>package com.claudeduguay.jmx.demo.client;<br><br>import java.util.*;<br><br>import javax.management.*;<br>import javax.management.remote.*;<br><br>public class SpringJmxClient implements NotificationListener<br>{<br>  public void handleNotification(<br>    Notification notification, Object handback) <br>  {<br>    System.out.println(<br>      "Notification: " + notification.getMessage());<br>  }<br>  <br>  public static void main(String[] args)<br>    throws Exception<br>  {<br>    SpringJmxClient listener = new SpringJmxClient();<br>    <br>    String address =<br>      "service:jmx:rmi:///jndi/rmi://localhost:8999/jmxrmi";<br>    JMXServiceURL serviceURL = new JMXServiceURL(address);<br>    Map&lt;String,Object&gt; environment = null;<br>    JMXConnector connector =<br>      JMXConnectorFactory.connect(serviceURL, environment);<br>    MBeanServerConnection mBeanConnection =<br>      connector.getMBeanServerConnection();<br>    <br>    ObjectName exampleServiceName =<br>      ObjectName.getInstance("Services:name=ExampleService");<br>    mBeanConnection.addNotificationListener(<br>      exampleServiceName, listener, null, null);<br>    <br>    mBeanConnection.invoke(<br>      exampleServiceName, "startService", null, null);<br>    mBeanConnection.setAttribute(exampleServiceName,<br>      new Attribute("propertyValue", "new value"));<br>    System.out.println(mBeanConnection.getAttribute(<br>      exampleServiceName, "propertyValue"));<br>    mBeanConnection.invoke(<br>      exampleServiceName, "stopService", null, null);<br>  }<br>} <br></code></pre></td></tr></tbody></table><br><p>由于 HTTP 适配器也是可用的，可以试着使用 MX4J
（通过一个到端口 8080 的浏览器连接）管理同样的方法和属性。如果同时让客户机代码运行，那么也会看到这些操作的通知。</p><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" width="16"><br></td><td align="right" valign="top"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-springjmx/#main"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br><br><p><a name="IDA4T4W"><span class="atitle">结束语</span></a></p><p>在
本文中，我展示了如何扩展 Spring 的 JMX 支持以满足应用程序的特定需求。在这里，我使用了 Spring 的基于容器的体系结构和
AOP 框架来为 JMX 方法和属性增加通知事件。当然，我只触及到了 Spring JMX 能力的皮毛。还可以有许多其他扩展，Spring 和
JMX 都是很大的主题，每一个都值得进一步研究。我建议您研究本文的源代码并参阅后面 <a href="http://www-128.ibm.com/developerworks/cn/java/j-springjmx/#resources">参考资料</a> 一节以了解更多关于 Spring JMX 和相关技术的内容。</p><br><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" width="16"><br></td><td align="right" valign="top"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-springjmx/#main"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br><br><p><span class="atitle"><a name="download">下载</a></span></p><table class="data-table-1" border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><th>描述</th><th>名字</th><th style="text-align: right;">大小</th><th>&nbsp;下载方法</th></tr><tr><td class="tb-row">Source code</td><td nowrap="nowrap">j-Extending-Spring-JMX.jar</td><td style="text-align: right;" nowrap="nowrap">22 KB</td><td nowrap="nowrap">
&nbsp;<a class="fbox" href="ftp://www6.software.ibm.com/software/developer/library/j-Extending-Spring-JMX.jar"><b>FTP</b></a></td></tr><tr><td class="tb-row">Source code</td><td nowrap="nowrap">j-Extending-Spring-JMX-src.zip</td><td style="text-align: right;" nowrap="nowrap">3 MB</td><td nowrap="nowrap">
&nbsp;<a class="fbox" href="ftp://www6.software.ibm.com/software/developer/library/j-Extending-Spring-JMX-src.zip"><b>FTP</b></a></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0"><tbody><tr valign="top"><td colspan="5"><img src="http://www.ibm.com/i/c.gif" alt="" border="0" height="12" width="12"></td></tr><tr><td><img src="http://www.ibm.com/i/v14/icons/fw.gif" alt="" height="16" width="16"></td><td><a href="http://www-128.ibm.com/developerworks/cn/whichmethod.html" class="fbox">关于下载方法的信息</a></td><td><img src="http://www.ibm.com/i/c.gif" alt="" height="1" width="50"></td><td><img src="http://www.ibm.com/i/v14/icons/sout.gif" alt="" height="16" width="16"></td><td><a href="http://www.adobe.com/products/acrobat/readstep2.html" class="fbox">获取 Adobe® Reader®</a></td></tr></tbody></table><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" width="16"><br></td><td align="right" valign="top"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-springjmx/#main"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br><br><p><a name="resources"><span class="atitle">参考资料 </span></a></p><b>学习</b><br><ul><li>您可以参阅本文在 developerWorks 全球站点上的 
          <a href="http://www-128.ibm.com/developerworks/java/library/j-springjmx/" target="_blank">英文原文</a>。<br><br></li><li><a href="http://www.ibm.com/developerworks/cn/java/j-aopwork10/">AOP@Work: 用 AspectJ 进行性能监视，第 1 部分</a> （Ron Bodkin，developerWorks，2005 年 9 月）：结合 AspectJ 与 JMX 以创建一个灵活的、面向方面的监视基础架构。<br><br></li><li><a href="http://www-128.ibm.com/developerworks/cn/opensource/os-lightweight2/">轻量级开发的成功秘诀，第 2 部分: 如何减轻容器</a> （Bruce Tate，developerWorks，2005 年 6 月）：解释大型体系结构（如 EJB）的不利之处和轻型容器的相对优点（系列）。<br><br></li><li><a href="http://www.martinfowler.com/articles/injection.html">
Inversion of Control Containers and the Dependency Injection  pattern</a>
（Martin Fowler，2004 年 1 月）：对于像 Spring 这样的轻型容器背后的注入模式进行详细分析。<br><br></li><li><a href="http://java.sun.com/products/JavaManagement/">JMX 主页</a>：直接从 Sun 公司学习更多关于 Java Management Extensions 的内容。<br><br></li><li><a href="http://java.sun.com/products/JavaManagement/best-practices.html">JMX Best Practices</a>：用 JMX API 进行建模的最佳实践。<br><br></li><li><a href="http://aopalliance.sourceforge.net/">AOP Alliance</a>：帮助和标准化在基于 Java 的中间件环境（如 J2EE）中使用 AOP 的工作。<br><br></li><li><a href="http://www.ibm.com/developerworks/cn/java/">Java 技术专区</a>：可以找到关于 Java 编程的各个方面的文章。<br><br></li></ul><br><b>获得产品和技术</b><br><ul><li><a href="http://www.springframework.com/">Spring framework</a> ：下载 Spring 框架和文档（现在的版本是 1.2）。<br><br></li><li><a href="http://mx4j.sourceforge.net/">MX4J</a>：JMX 标准的一个重要开放源码实现。<br><br></li><li><a href="http://www.alphaworks.ibm.com/tech/mbeaninspector">MBeanInspector for WebSphere</a>：源自 alphaWorks 的针对 WebSphere 5 的基于 JMX 的管理程序。<br><br></li></ul><br><b>讨论</b><br><ul><li>加入本文的<a href="javascript:void forumWindow()">论坛</a> 。(您也可以通过点击文章顶部或者底部的论坛链接参加讨论。)<br><br></li><li><a href="http://www.ibm.com/developerworks/blogs/">developerWorks blogs</a>：参加 developerWorks 社区。
</li></ul><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%"></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" width="16"><br></td><td align="right" valign="top"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-springjmx/#main"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br><br><p><a name="author"><span class="atitle">关于作者</span></a></p><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td colspan="2"><img src="http://www.ibm.com/i/c.gif" alt="" height="5" width="100%"></td></tr><tr align="left" valign="top"><td><p><img alt="" src="http://www.ibm.com/developerworks/i/p-cduguay.jpg" align="left" height="80" width="64"></p></td><td><p>Claude
是 Capital Stream Inc 的高级 J2EE 架构师。他有超过 25 年的软件开发经验，并且在 Java 平台的第一个 beta
版本发布时就开始使用它了。Claude 已发表了超过 75 篇文章和 超过 150 篇书评，主要关注 Java 语言和 XML。 </p></td></tr></tbody></table></td></tr></tbody></table><img src ="http://www.blogjava.net/ericwang/aggbug/23230.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ericwang/" target="_blank">Dion</a> 2005-12-09 23:23 <a href="http://www.blogjava.net/ericwang/archive/2005/12/09/23230.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>