- 浏览: 276812 次
文章分类
最新评论
-
guji528:
oracle的统计函数真的很强大
Oracle 使用LAG和LEAD函数统计 -
haiyangyiba:
受教了
No Dialect mapping for JDBC type: 3 -
elvishehai:
能不能给个完整点的例子呀,我一直都没有试成功过,
简单的使用jackson的annotation -
miaoyue:
如果我想把name属性转成注释之后,之前的注释还在怎么做?
PowerDesigner 中将Comment(注释)及Name(名称)内容互相COPY的VBS代码 -
ianl_zt:
以上方法只适合在hibernate2中使用,现在hiberna ...
Hibernate的批量更新和删除
1.引言
SOA是一种构造分布式系统的方法,它将业务应用功能以服务的形式提供出来,以便更好的复用、组装和与外部系统集成,从而降低开发成本,提高开发效率。SOA的目标是为企业构建一个灵活,可扩展的IT基础架构来更好地支持随需应变的商务应用。
随着SOA技术和产品的不断成熟,现在越来越多的用户开始了解并认同SOA的理念,但对SOA项目的实施还缺乏信心。其主要原因是:SOA应用开发还相对比较复杂。
一年多来,本文作者所在的部门已经从事了许多国内外的SOA项目的实施和支持工作,积累了许多SOA应用开发经验。我们希望能够通过一系列的文章与读者分享这些想法,帮助您更好地构建SOA应用。
本 文将从Web Service调用入手,在解决一系列具体问题的过程中,使用IoC (Inversion of Control) 和AOP (Aspect- Oriented Programming) 等方法重构Web Service的访问代码,使得业务逻辑与Web Service访问解耦,为您提供一个更加灵活和易于扩展的访问模式。
Spring是一个流行的轻量级容器,对IoC和AOP提供了良好的 支持。本文为您提供了一个基于Spring的实现供您下载学习。示例代码工程使用Eclipse3.1/3.02和JDK1.4开发, 您还需要Spring 1.2.5和Axis1.3提供的支持。详细的下载信息请参见参考资源部分。
2.Web Service调用
Web Service是目前实现SOA应用的一项基本的,适用的技术,它为服务的访问提供了一个被广泛接受的开放标准。为了便于说明问题,我们将使用XMethods 网站(http://www.xmethods.net/)发布的货币兑换服务作为示例。并针对JAX-RPC 1.1,说明如何编写Web Service 的调用代码。
2.1 示例说明
http://xmethods.net 作为最早推出Web Service实际示例的网站,提供了很多优秀的Web Service 样例。其中有一个汇率计算服务,可以返回两个国家之间的货币兑换比例。获取该服务的详细信息,请参考该服务的服务描述文档(获取WSDL 文档) 。在此就不具体解析该服务描述文档了。读者可以从WSDL2Java生成的接口中了解该服务的用法:
public interface CurrencyExchangePortType extends java.rmi.Remote {
public float getRate(String country1, String country2) throws java.rmi.RemoteException;
}
2.2 客户端调用方法
JAX -RPC作为Java平台的RPC服务调用标准接口,为Web Service客户端调用提供了3种方法,分别是DII,动态代理,和静态Stub。 DII(Dynamic Invocation Interface)采用直接调用方式,可以在程序中设置诸多的调用属性,使用较为灵活,但是调用过程却相对繁琐复杂,易造成代码膨胀且可重用性低,每次 调用不同的Web Service都要重复进行大量编码。
JAX-RPC中动态代理(Dynamic Proxy)的方法实现对Web Service的动态调用,可以在运行时根据用户定义的Client端接口创建适配对象。从而避免了直接操作底层的接口,减少了客户端的冗余,屏蔽了调用相关的复杂性。
使 用静态Stub和Service Locator是目前最常用的调用方式。JAX-RPC使用静态的Stub方式包装对底层接口的调用,从而提供一种更为简便的调用方式。使用该方式需要利 用支持环境(比如Axis)所提供的工具根据WSDL预生成Web Service客户端的实现代码。因此如果服务的WSDL发生变化,就必须重新生成新的客户端代码并进行重新部署。
为了更详细的了解静态Stub的调用方式,您可以将示例代码的WebServiceClient.jar导入到您现有Eclipse工作区之中。
客户端生成代码包括如下4个类:如图 1 所示:
图 1: 客户端代码类图
在上图中包括的几个类中:
CurrencyExchangePortType:服务端点接口,定义了Web Service的方法签名。
CurrencyExchangeService:Service接口,定义了获取服务端点接口的方法。
CurrencyExchangeServiceLocator:ServiceLocator类,实现了Service接口。
CurrencyExchangeBindingStub: Stub实现类,实现了服务端点接口,封装了对Web Service访问的底层逻辑。
使用Stub调用Web Service的过程也非常简单,读者可以参考清单 1:
清单 1:Web Service 调用代码示例
try {
//创建ServiceLocator
CurrencyExchangeServiceLocator locator = new
CurrencyExchangeServiceLocator();
//设定端点地址
URL endPointAddress = new URL("http://services.xmethods.net:80/soap");
//创建Stub实例
CurrencyExchangePortType stub =
locator.getCurrencyExchangePort(endPointAddress);
//设定超时为120秒
((CurrencyExchangeBindingStub)stub).setTimeout(120000);
//调用Web Service计算人民币与美元的汇率
float newPrice = stub.getRate("China", "USA") * 100;
} catch (MalformedURLException mex) {
//...
} catch (ServiceException sex) {
//...
} catch (RemoteException rex) {
//...
}
3.重构Web Service调用代码
3.1 实例代码中的"坏味道"
上面的基于Service Locator的Web Service访问代码虽然简单但暴露出以下几个问题:
1.访问Web Service所需的配置代码被嵌入应用逻辑之中
在Web Service调用中,我们需要设定一系列必要的参数。比如:服务端点地址、用户名/密码、超时设定等等。这些参数在开发和运行环境中都有可能发生变化。我们必须提供一种机制:在环境变化时,不必修改源代码就可以改变Web Service的访问配置。
2 客户端代码与Web Service访问代码绑定
在 上面的代码中,业务逻辑与Web Service的Stub创建和配置代码绑定在一起。这也不是一种良好的编程方式。客户端代码只应关心服务的接口,而不应关心服务的实现和访问细节。比 如,我们既可以通过Web Service的方式访问远程服务,也可以通过EJB的方式进行访问。访问方式对业务逻辑应该是透明的。
这种分 离客户端代码与服务访问代码的方式也有利于测试。这样在开发过程中,负责集成的程序员就可能在远程服务还未完全实现的情况下,基于服务接口编写集成代码, 并通过编写POJO(Plain Old Java Object)构建伪服务实现来进行单元测试和模拟运行。这种开发方式对于保证分布式系统代码质量具有重要意义。
因此,为了解决上面的问题我们需要:
1、将Web Service访问的配置管理与代码分离;
2、解除客户端代码与远程服务之间的依赖关系;
3.2 利用IoC模式进行重构代码
我 们先介绍在Core J2EE Patterns一书中提到的一种业务层模式:Business Delegate。它所要解决的问题是屏蔽远程服务访问的复杂性。它的主要思想就是将Business Delegate作为远程服务的客户端抽象,隐藏服务访问细节。Business Delegate还可以封装并改变服务调用过程,比如将远程服务调用抛出的异常(例如RemoteException)转换为应用级别的异常类型。
其类图如图 2 所示:
图 2:Business Delegate 模式的类图图解
Business Delegate模式实现很好地实现了客户端与远程访问代码的解耦,但它并不关注Delegate与远程服务之间的解耦。为了更好解决Business Delegate和远程服务之间的依赖关系,并更好地进行配置管理,我们可以用IoC模式来加以解决。
IoC(Inversion of Contro)l意为控制反转,其背后的概念常被表述为"好莱坞法则":"Don't call me, I'll call you." IoC将一部分责任从应用代码交给framework(或者控制器)来做。通过IoC可以实现接口和具体实现的高度分离,降低对象之间的耦合程度。 Spring是一个非常流行的IoC容器,它通过配置文件来定义对象的生命周期和依赖关系,并提供了良好的配置管理能力。
现在我们来重构我们的Web Service应用程序,我们首先为Business Delegate定义一个接口类型,它提供了一个应用级组件接口,所有客户端都应通过它来执行汇率计算,而不必关心实现细节,如清单 2 所示:
清单 2:接口定义的代码示例
Public interface CurrencyExchangeManager {
//货币兑换计算
//新价格 = 汇率 * 价格
public float calculate(String country1, String country2, float price)
throws CurrencyExchangeException;
}
Business Delegate的实现非常简单,主要工作是包装汇率计算 Web Service的调用,如清单 3 所示。
清单 3:Business Delegate的代码示例
public class CurrencyExchangeManagerImpl implements CurrencyExchangeManager {
//服务实例
private CurrencyExchangePortType stub;
//获取服务实例
public CurrencyExchangePortType getStub() {
return stub;
}
//设定服务实例
public void setStub(CurrencyExchangePortType stub) {
this.stub = stub;
}
//实现货币兑换
public float calculate(String country1, String country2, float price)
throws CurrencyExchangeException {
try {
//通过Stub调用WebService
float rate = stub.getRate(country1, country2);
return rate * price;
} catch (RemoteException rex) {
throw new CurrencyExchangeException(
"Failed to get exchange rate!", rex);
}
}
}
下面我们需要讨论如何利用Spring的IoC机制,来创建和配置对象,并定义它们的依赖关系。
Spring 利用类工厂来创建和配置对象。在Spring框架中,已经为基于JAX-RPC的Web Service调用提供了一个客户端代理的类工厂实现:JaxRpcPortProxyFactoryBean。在配置文件bean.xml中,我们将使 用JaxRpcPortProxyFactoryBean来创建和配置Web Service的客户端代理"CurrencyExchangeService",如清单 5 所示。我们还将定义一个名为"CurrencyExchangeManager"的CurrencyExchangeManagerImpl实例,并建立 它与CurrencyExchangeService之间的依赖关系。有关Spring 配置和JaxRpcPortProxyFactoryBean的使用细节请参见参考资料。
清单 5:bean.xml的配置文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="CurrencyExchangeService"
class="org.springframework.remoting.jaxrpc.JaxRpcPortProxyFactoryBean">
<property name="serviceInterface">
<value>net.xmethods.www.sd.CurrencyExchangeService_wsdl.
CurrencyExchangePortType</value>
</property>
<property name="wsdlDocumentUrl">
<value>http://www.xmethods.net/sd/2001/CurrencyExchangeService.
wsdl</value>
</property>
<property name="namespaceUri">
<value>http://www.xmethods.net/sd/CurrencyExchangeService.
wsdl</value>
</property>
<property name="serviceName">
<value>CurrencyExchangeService</value>
</property>
<property name="portName">
<value>CurrencyExchangePort</value>
</property>
<property name="endpointAddress">
<value>http://services.xmethods.net:80/soap</value>
</property>
</bean>
<bean id="CurrencyExchangeManager"
class="test.ws.CurrencyExchangeManagerImpl">
<property name="stub">
<ref bean="CurrencyExchangeService"/>
</property>
</bean>
</beans>
最后我们创建一个测试程序来验证我们的代码,如清单6 所示:
清单 6:测试代码
public class Main {
// For test only
public static void main(String[] args) {
// Spring Framework将根据配置文件创建并配置CurrencyExchangeManager实例
ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");
// 获取CurrencyExchangeManager实例
CurrencyExchangeManager manager = (CurrencyExchangeManager) ctx
.getBean("CurrencyExchangeManager");
try {
System.out.println(manager.calculate("China", "USA", 100));
System.out.println(manager.calculate("China", "Japan", 200));
System.out.println(manager.calculate("China", "USA", 200));
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
此时运行测试客户端,等待片刻将会看见测试结果,如清单 7 所示:
清单 7:测试结果。
12.34
2853.26
24.68
注:该结果会随着汇率的变化而出现不同的值。
该程序的类图和顺序图如图3及图4所示:
图 3:示例程序的类图
从 上面的类图我们可以看到,我们的测试程序(Main.java)通过Spring框架获取了BusinessDelegate的实例。而且Spring 框架还会根据配置中的依赖关系,在运行时将Web Service的客户端代理" 注射"到CurrencyExchangeManagerImpl实例中,这就是依赖注入(Dependency Injection)。通过这种方式解决了应用逻辑和BusinessDelegate之间的依赖关系,以及BusinessDelegate的实现与远 程服务之间的依赖关系,如图 4 所示。
图 4: 示例程序的顺序图
Spring 框架提供的ApplicationContext实现会根据配置文件中的描述信息来实现对象生命周期管理,配置管理以及依赖管理等功能。这一切对于应用程 序是透明的,应用程序代码只依赖接口进行编程,而无需考虑其它复杂问题。无论是Web Service的配置发生变化,或是改用不同的服务实现时,都不会对客户端应用代码的产生影响。这很好地实现了业务逻辑与Web Service调用之间的解耦。
3.3 构建自己的 Web Service代理工厂
Spring所提供的 JaxRpcPortProxyFactoryBean封装了构造Web Service客户端代理的细节,可以通过参数配置来创建Dynamic Proxy和DII类型的Web Service客户端代理。(如果您希望深入了解其实现细节可以参考org.springframework.remoting.jaxrpc包下的源代 码。)但由于JaxRpcPortProxyFactoryBean需要使用者对WSDL中Port,Service,名空间等概念有深入的了解;而且如 果Web Service使用了复杂数据类型,开发人员需要手工定义类型映射代码。所以JaxRpcPortProxyFactoryBean并不适合Web Service的初学者来使用。
为了进一步简化Web Service代理的创建,并帮助读者更好地理解类工厂在Spring框架下的作用。我们提供了一个基于静态Stub的Web Service客户端代理工厂实现。其核心代码非常简单,就是通过ServiceLocator提供的方法来创建Web Service客户端代理。
其主要代码如清单8所示:
清单8:静态代理工厂的代码
public class WebServiceStubFactoryBean implements FactoryBean,
InitializingBean {
private Class serviceInterface;
private Class serviceLocator;
private Object stub;
…
public void afterPropertiesSet() throws Exception {
//利用serviceLocator和服务接口创建Web Service客户端代理
stub = ((javax.xml.rpc.Service)
serviceLocator.newInstance()).getPort(serviceInterface);
//为Stub设定endpointAddress,usernam, 超时等参数
preparePortStub((javax.xml.rpc.Stub) stub);
}
public Object getObject() {
// 返回客户端代理
return stub;
}
public Class getObjectType() {
// 返回服务接口
return serviceInterface;
}
public boolean isSingleton() {
return true;
}
}
我们需要修改配置文件bean.xml中有关Web Service代理创建的部分,让新的Web Service 代理工厂发挥作用。如清单9所示:
清单9:修改后的bean.xml的配置文件
<bean id="CurrencyExchangeService" class="test.ws.WebServiceStubFactoryBean">
<property name="serviceInterface">
<value>net.xmethods.www.sd.CurrencyExchangeService_wsdl.CurrencyExchangePortType</value>
</property>
<property name="serviceLocator">
<value>net.xmethods.www.sd.CurrencyExchangeService_wsdl.CurrencyExchangeServiceLocator</value>
</property>
<property name="endpointAddress2">
<value>http://services.xmethods.net:80/soap</value>
</property>
<property name="timeout">
<value>120000</value>
</property>
</bean>
得益于Spring框架,虽然我们已经替换了对象的类工厂,却并不需要更改应用代码。通过Spring框架的IoC机制,我们可以完全使用面向接口的编程方式,而将实现的创建、配置和依赖管理交由Spring在运行时完成。即使实现发生了变化,也不需要改变应用程序结构。
4.新的思考
故事并没有结束,在开发过程中,我们又遇到了一系列关于Web Service调用的问题。
4.1性能
系 统性能是分布式应用中的一个重要问题。许多用户都担心由Web Service技术所引入的额外开销是否会影响到产品的性能。随着技术的不断发展,Web Service引擎性能已经有了很大提高,一般来说使用Web Service的系统的性能可以满足绝大部分应用的需求。但在特定情况下,如果系统性能无法满足客户需求,我们首先需要对系统性能进行科学地分析和测定才 能定位真正的性能瓶颈。这个问题在上文简单的示例中并不难解决,只需要在Web Service调用前后加入日志代码记录调用时间即可实现。但在实际系统中,比如一个产品目录的Web Service可能提供数十种查询方法,而程序中很多组件都会依赖于该服务提供的查询功能。如果在系统中所有的地方加入性能测定代码,这个工作就变得非常 繁琐和困难。我们需要用一种更加优雅的解决方式,在增添新功能的同时并不影响系统代码或结构。
4.2缓存
在项目实践中,一个有效的 改善Web Service系统性能的方法就是利用缓存来减少Web Service的重复调用。在具体实现中我们可以采用客户端缓存和服务器端缓存等不同方式,他们具有不同的特点和适用范围。在本文例子中,我们希望实现客 户端缓存来提高系统性能。但由于Web Service业务逻辑的差别,我们希望能够为特定的Web Service提供特定的缓存策略,而且这些策略应该是能够被灵活配置的,它们不应于应用程序的逻辑代码耦合在一起。
4.3故障恢复:
对 于Web Service应用,系统的可用性也是一个需要考虑的重要问题。在运行时由于网络运行环境的复杂性和不确定性,用户希望能够对Web Service访问提供一定的故障恢复机制:比如重试或者访问备份服务(当系统在调用Web Service失败后,使用备份Web Service的服务地址来继续访问)。这些故障恢复策略应该是可配置的,对应用逻辑透明的。
5.使用AOP解决SOA应用中的Crosscutting Concern
通过对上边一系列问题的分析,读者也许会发现这些问题并不是Web Service访问的核心问题,但会影响系统中许多不同的组件。而且其中一些问题需要我们能够灵活配置不同的实现策略,因此我们不应该将处理这些问题的代码与应用代码混合。
下 面我们将利用AOP(Aspect-Oriented Programming)提供的方法来解决上述的问题。AOP是一种新兴的方法学,它最基本的概念就是关注隔离(Separation of Concern)。AOP提供了一系列的技术使得我们能够从代码中分离那些影响到许多系统模块的crosscutting concerns,并将他们模块化为Aspects。AOP的主要目的仍然是解耦,在分离关注点后,才能将关注点的变更控制一定范围内,增加程序的灵活 性,才能使得关注能够根据需求和环境作出随时调整。
我们将利用Spring所提供的AOP功能支持来解决以上问题。这里我们只简单地介绍涉及到的AOP基本概念以及实现,如果您希望更好地了解AOP的概念以及Spring AOP支持的细节请参见参考资料。
• Joinpoint 是程序的运行点。在Spring AOP中,一个Joinpoint对应着一个方法调用。
• Advice 定义了AOP框架在特定的Joinpoint的处理逻辑。Spring AOP框架通过interceptor方式实现了advice,并且提供了多种advice类型。其中最基本的"around advice"会在一个方法调用之前和之后被执行。
下面我们将利用Spring提供的MethodInterceptor来为Web Service调用实现我们的定义的处理逻辑。
5.1 PerformanceMonitorInterceptor
性能测量是AOP最简单的例子之一,我们可以直接利用Spring提供的实现在bean.xml中声明我们的WebServicePerformanceMonitorInterceptor。
5.2 CacheInterceptor
为 了不引入缓存策略的复杂性,我们只提供了一个利用HashMap的简单实现:它利用 Web Service的调用参数列表作为HashMap键值。在Web Service调用之前,首先检查缓存中是否拥有与现在参数列表相同的项,如果有则返回缓存的结果,否则调用Web Service并将<参数列表,结果>记录在HashMap中。在实际应用中,您应该根据具体情况来选择、构造适合Web Service的业务特性的Cache实现,也可以采用成熟的Cache实现。
在下面代码实现中有一个生成Web Service调用主键的小技巧。因为Web Service引擎要求所有调用参数必须是可序列化的,所以我们可以利用Java提供的序列化功能来实现对象的克隆。如清单10所示:
清单10:SimpleCacheInterceptor的代码示例
public class SimpleCacheInterceptor implements MethodInterceptor {
private Map cache = new HashMap();
private Object cloneObject(Object obj) throws Exception {
Object newObj = null;
if (obj != null) {
// 通过序列化/反序列化来克隆对象
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(obj);
out.flush();
out.close();
ObjectInputStream in = new ObjectInputStream(
new ByteArrayInputStream(bos.toByteArray()));
newObj = in.readObject();
}
return newObj;
}
//基于参数列表数组,生成用于HashMap的键值
public Object generateKey(Object[] args) throws Exception {
Object[] newArgs = (Object[]) cloneObject(args);
List key = Arrays.asList(newArgs);
return key;
}
//实现使用缓存技术的invoke方法
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
Object result = null;
Object data = null;
Object key = null;
try {
key = generateKey(methodInvocation.getArguments());
data = cache.get(key);
} catch (Exception ex) {
logger.error("Failed to find from the cache", ex);
}
if (data == null) {
//如果Cache中没有缓存结果,调用服务执行生成用于HashMap的键值
result = methodInvocation.proceed();
try {
data = cloneObject(result);
cache.put(key, data);
} catch (Exception ex) {
logger.error("Failed to cache the result!", ex);
}
} else {
result = data;
}
return result;
}
}
5.3 FailoverInterceptor
下面代码提供了一个基于服务备份切换的故障恢复实现,在运行时,如果Interceptor检测到服务调用由于网络故障抛出异常时,它将使用备份服务的端点地址并重新调用。如清单11所示:
清单 11: SimpleFailoverInterceptor的代码示例
public class SimpleFailoverInterceptor implements MethodInterceptor { …
…
//实现支持端点运行时切换的invoke方法
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
Object result = null;
try {
result = methodInvocation.proceed();
} catch (Throwable ex) {
if (isNetworkFailure(ex)) {
//切换服务端点地址
switchEndPointAddress((Stub) methodInvocation.getThis());
result = methodInvocation.proceed();
} else {
throw ex;
}
}
return result;
}
}
为了支持备份服务切换的功能,我们在WebServicePortProxyFactoryBean中为填加了配置参数"endpointAddress2",它会在创建的Web Service客户端代理对象中记录备份URL。
我 们可以在CurrencyExchangeService加入下列参数来试验SimpleFailoverInterceptor的功能。其中第一个端点 地址为一个错误的URL。在第一次调用服务时,SimpleFailoverInterceptor会侦测到网络故障的发生,并自动切换使用第二个端点地 址继续访问。如清单12所示:
清单12:配置文件种增加的属性
<property name="endpointAddress">
<value>http://localhost/wrong_endpoint_address</value>
</property>
<property name="endpointAddress2">
<value>http://services.xmethods.net:80/soap</value>
</property>
5.4配置文件和运行结果
现 在我们需要在Spring配置文件中,为所有interceptor添加定义,并描述如何为CurrencyExchangeService构建AOP Proxy。需要指出的是,我们要在interceptorName列表中声明interceptor链的调用顺序,还要将原有 CurrencyExchangeManager引用的stub对象替换为新AOP Proxy。如清单13所示:
清单13:修改后的配置文件片段
<bean id="WebServicePerformanceMonitorInterceptor"
class="org.springframework.aop.interceptor.PerformanceMonitorInterceptor">
<property name="prefix">
<value>Web Service </value>
</property>
<property name="suffix">
<value></value>
</property>
</bean>
<bean id="CacheInterceptor" class="test.ws.SimpleCacheInterceptor"/>
<bean id="FailoverInterceptor" class="test.ws.SimpleFailoverInterceptor"/>
<bean id="CurrencyExchangeProxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>net.xmethods.www.sd.CurrencyExchangeService_wsdl.
CurrencyExchangePortType</value>
</property>
<property name="target">
<ref local="CurrencyExchangeService"/>
</property>
<property name="interceptorNames">
<list>
<value>WebServicePerformanceMonitorInterceptor</value>
<value>CacheInterceptor</value>
<value>FailoverInterceptor</value>
</list>
</property>
</bean>
<bean id="CurrencyExchangeManager"
class="test.ws.CurrencyExchangeManagerImpl">
<property name="stub">
<ref bean="CurrencyExchangeProxy"/>
</property>
</bean>
这 里我们通过为AOP 的ProxyFactoryBean为 Web Service Stub创建了一个AOP代理,并且建立了一个Interceptor链。这样在调用Web Service时,Spring框架会依次调用Interceptor执行。实例执行的顺序图将如图5所示:
图5系统运行顺序图
5.5 Interceptor与JAX-RPC Handler的关系与区别
SOAP Message Handler是JAX-RPC为用户自定义Web Service处理过程提供的一种扩展机制。在处理Web Service请求/响应过程中,Web Service 引擎会根据部署描述中的定义,按照一定的次序调用Handler的处理代码。用户编写的Handler实现可以截获并修改Web Service消息和处理流程,从而实现对Web Service引擎处理行为的定制和增强。
比如,我们可以实现一个服务器端Handler,记录Web Service在受到请求消息和发出响应消息之间的时间间隔来实现对服务器端业务性能的测定。而且我们只需在部署描述中增加Handler声明即可,无需修改任何服务器端代码。
从 此可以看出,JAX-RPC Handler与我们在上文中所提供的AOP Interceptor都可以帮助我们的SOA应用程序实现关注分离(Separate Concern)的目标,在不改变应用代码的同时,增强或改变Web Service服务访问的功能。虽然我们可以利用它们实现一些类似的功能,但它们具有着不同的特点和适用范围。
JAX-RPC Handler是Web Service引擎的扩展机制。如果我们需要实现对SOAP消息进行的修改和处理,加入自定义的SOAP Header或对消息内容进行加密,Handler是我们的最佳选择。而AOP是针对对象级别的扩展机制,它更适合对应用层逻辑进行操作。
比 如,我们在上文展示的利用AOP实现的CacheInterceptor,它缓存的是Web Service调用参数和结果。而我们也可以通过JAX-RPC Handler实现一个面向SOAP消息的实现,它将缓存Web Service的请求消息和响应消息。这两个实现相比,基于AOP的实现更加简单、直观、快速、对资源消耗也比较小。而面向SOAP消息的实现则更加灵 活,对于不采用RPC方式的Web Service访问也能提供支持。
所以在具体的实践过程中,开发人员应该根据具体的需求选择合适的技术,也可以将这两种技术结合使用。
6.总结
"分而治之"的方法是人们解决复杂问题的一种常见做法。而IoC、AOP等技术都体现了这种思想。通过更好的切分程序逻辑,使得程序结构更加良好,更加富有弹性,易于变化。也使得开发人员可以更加专注于业务逻辑本身,而将一部分其他逻辑交给容器和框架进行处理。
在本文中,我们通过一个Web Service访问的实例,具体描述了SOA应用中所遇到的一系列具体问题,并描述如何利用IoC和AOP等技术进行代码重构,构建更加结构良好、灵活的SOA应用。综上所述,我们可以看到:
1使用IoC框架来实现对象的生命周期管理、配置管理和依赖管理,可以解除业务逻辑对服务调用的依赖关系;
2 使用AOP方法来解决Web Service调用中的crosscutting concerns,将为系统增加新的功能而不必更改应用程序。
3通过IoC和AOP来屏蔽Web Service访问的复杂性,使得开发人员可以更加专注于业务逻辑本身,也使得系统更加稳定和富有弹性。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ruixj/archive/2006/04/26/678264.aspx
评论
但是webservice!=SOA,SOA是为了业务多变性的解决方案,才是分而治之的思想,归根道理由业务决定。采用SOA思想是为了隔离变化、提高开发效率,但是同时也增加了很多成本,比如事务一致性、性能,如果划分的系统很多,服务可能会像蜘蛛网一样,这时需要服务监控、治理等。
发表评论
-
AnnotationFormatError when using Spring 3.0 & JavaConfig
2011-02-25 10:52 5781Spring 3.0M3 及其以后的版本包含 ... -
Spring Schemas and Namespaces
2010-05-11 11:34 5986本章研究Spring命名空间,你将学到新的并且更简单的办 ... -
Spring 中的一些事务注解属性
2010-01-11 10:36 4252用 spring 事务管理器, ... -
Spring 3.0呼之欲出
2009-10-28 10:20 3222业界最著名使用最广泛的开源Java框架Spring宣布推出3. ... -
CXF jaxws spring configuration
2009-08-27 11:35 4807如果大家只是想了解如何写jaxws:endpoint 配置文件 ... -
Spring 2.5新特性(2)-Spring MVC中的新特性
2009-08-20 11:06 3928Spring框架从创建伊始就 ... -
Spring 2.5的新特性(1):配置简化和基于注解的功能
2009-08-20 10:55 4088简介 从诞生之初,Spring框架就坚守它的宗旨:简化企业级 ... -
Spring 2.5新特性及架构图
2009-07-03 09:04 3665Spring2.5是Spring2.1各个里程碑版本的终结。 ... -
Spring 2.5.6新特性之packagesToScan
2009-07-03 08:58 3199如果你使用早前版本的Spring,又恰好采用了Annotati ... -
Spring2.5注解实现AOP
2009-07-02 11:33 3271这个例子非常的简单,下面是实体类 package test; ... -
图解Spring Security默认使用的过滤器
2009-06-15 11:03 3853首先看一下auto-config="tr ... -
使用 Spring 2.5 TestContext 测试框架
2009-04-29 16:41 3045Spring 2.5 TestContext 测试框架用于测试 ... -
Spring 2.5 Annotation
2009-04-07 11:44 3315基于注释(Annotation) ... -
spring 注解
2009-04-01 09:33 3076Spring JSR-250注解 注释配 ... -
Spring2.0用注解实现事务管理
2009-04-01 09:31 4414Spring2.0框架的事务处理有两大类: 1 编码式事务 ... -
Spring技巧之简洁配置
2009-01-09 11:08 3278Spring2.0在配置上调整了不少地方,增加更加灵活、简洁的 ... -
spring框架使用任务调度quartz的例子-TriggerListener 篇
2008-09-04 21:31 2580有时候我们的任务(Job)需要再某些任务完成之后 ... -
spring框架使用任务调度quartz的例子-Job and Trigger 篇
2008-09-04 21:21 2291MainJob.java 1package jobs; 2 ... -
基于struts+spring+ibatis的轻量级J2EE开发
2008-08-29 09:17 2106JpetStore 4.0是ibatis的最新示例程序,基于S ... -
关于IntrospectorCleanupListener
2008-08-15 10:28 3555spring中的提供了一个名为org.springframew ...
相关推荐
SPRING AND SOA 的网页呵呵
#### 二、SOA与SCA简介 **SOA**是一种设计模式,它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来。接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台、操作...
综上所述,“SCA服务构件架构Spring构件实现规范.pdf”这份文档很可能会详细阐述如何利用Spring框架来实现SCA的各个组成部分,包括服务的定义、组合、生命周期管理以及与SOA的结合,为Java开发者提供了一条实现服务...
基于Spring框架的SOA系统架构的实现最终版.pdf
2. **与Spring的紧密集成**:XFire可以无缝集成到Spring环境中,利用Spring的依赖注入和事务管理。 3. **支持多种协议**:XFire支持SOAP、REST等多种通信协议,满足不同需求。 4. **动态服务**:XFire允许动态创建...
标题中的“FF.MSOL.SOA.rar_jpa hibernate_spring hibernate_spring mvc”表明这是一个关于Java企业级开发的资源包,其中涉及到的主要技术栈是JPA(Java Persistence API)、Hibernate、Spring以及Spring MVC。...
本章将讨论SOA与Web服务的关系,解释如何使用SOAP、RESTful等Web服务技术实现SOA,并分析两者之间的优缺点。 ### 第八章:SOA实施工具和技术 本章将介绍常用的SOA工具,如IBM WebSphere、Oracle SOA Suite等,并...
Spring Cloud 学习笔记 本笔记主要介绍了从单体架构到微服务架构的演变过程,以及 Spring Cloud 中的微服务架构搭建。下面是本笔记的详细知识点总结: 一、单体架构 单体架构是指整个系统只有一个工程,打包往往...
在SOA环境中,跨服务的事务处理需要考虑分布式事务,Spring的JtaTransactionManager可以处理这种情况。 7. **安全性与权限控制** SSH框架中的Spring Security或Struts的拦截器可以用于用户认证和授权。在SOA系统中...
Spring框架提供了一套完整的SOA解决方案,包括Spring-WS(用于创建契约优先的Web服务)和Spring-Integration(支持ESB(Enterprise Service Bus)功能)。Spring-WS基于XML Schema,允许开发者以类型安全的方式定义...
Spring Cloud Alibaba 是Spring Cloud生态的一部分,它为开发者提供了与Spring Boot无缝集成的微服务组件,让开发者可以更加便捷地构建云原生应用。 在学习Spring Cloud Alibaba的过程中,你需要掌握以下几个关键...
开源软件如Apache CXF、Spring框架等,为构建和部署SOA服务提供了成本效益高的选择,同时也保持了灵活性和可扩展性。 **RESTful Java Web Services**:REST(Representational State Transfer)是一种轻量级的架构...
【标题】"cxf2.7+spring4" 指的是Apache CXF 2.7版本与Spring框架4.1.5版本的整合应用。Apache CXF是一个开源的Java框架,主要用于构建和开发服务导向架构(SOA)中的Web服务。而Spring框架则是一个广泛使用的Java...
7. **工具和框架**:例如,Apache CXF、Spring Integration、IBM WebSphere ESB等,它们提供了实现SOA所需的功能和支持。 在阅读《解析SOA思想与相关技术》这本书时,读者将深入理解这些概念和技术,并学习如何在...
Spring框架提供了全面的SOA支持,包括Spring-WS、Spring-Integration等模块,使得服务的开发、管理和集成变得更加简单。 **4. 源码和工具** 在学习和实践中,深入理解源码有助于更好地掌握SOA的实现机制。例如,...
在SOA中,每个服务都有明确的边界,提供特定的功能,并通过标准的接口与其它服务进行交互。这种架构模式允许企业灵活地构建和扩展其IT基础设施,提高服务复用性,降低维护成本,以及促进业务流程的敏捷性。 在"SOA....
1. **SOA基础概念**:介绍SOA的核心原则、目标和优势,以及它与传统的软件架构的区别。 2. **Web服务技术**:详细阐述SOAP、WSDL和UDDI的工作原理,以及如何利用它们构建和消费Web服务。 3. **服务设计与治理**:...
2. **WebServiceClient.jar** - 此文件可能是用来消费其他服务的Web服务客户端库,这在SOA环境中很常见,用于与不同的服务进行交互。 3. **CurrencyExchange.jar** - 另一个可能包含原始或未重构的货币兑换服务的JAR...