先看一下tuscany简介,简单了解一下tuscany是什么
SCA 的基本概念以及 SCA 规范的具体内容并不在本文的范畴之内,有兴趣的读者可以通过一些相关文档了解相关内容,这也是阅读本文的基础。下面本文首先对 Tuscany 框架做一定的介绍。
Tuscany 是 Apache 的开源项目,它是 IBM、Oracle、SAP 等厂商联合成立的 SOA 标准化组织 -OSOA 支持下开发出的 SCA 框架,它既是开源界 SCA 的试金石,也是当前开源界最成熟的 SCA 框架之一。
tuscany是一套开源的sca框架模型,是做soa的基础架构
SCA是什么?
SCA为构建基于SOA的应用和解决方案提供了编程模型。它基于这样的理念:将业务功能作为一系列的服务而提供,并由这一系列的服务组装起来的解决方案来满足特定业务需求。这些组合的应用既包括为应用而新创建的特定服务,也包括源自已已存在系统和应用的业务逻辑,这些业务逻辑作为组合构件的一部分被复用。SCA既为服务的组合也为服务构件的创建提供了模型,包括对SCA组组合构件中对已存在应用功能的复用。
SCA的基础工件就是component,它是SCA的构成单元。构件(component)由一个实现的可配置(implementation)实例所组成。在该构件中,实现是提供业务功能的程序代码片段。该业务功能作为服务(service)而提供,为其他构件所使用。实现也许依赖于由其他构件所提供的服务,这些依赖被称作”引用”(reference)。实现可以有一个可设置的属性(properties),该属性是可以影响业务功能操作的数据值。构件通过提供属性值和连线(wire)到由其他构件提供服务的引用来配置实现。
还是通过实例来看一下SCA到底实现了什么样的功能吧!
看一下发布一个基本的加减乘除的示例,这个是tuscany的官方示例
定义一个接口实现基本的计算器功能
定义接口CalculatorService,实现基本的加减乘除
public interface CalculatorService { double add(double n1, double n2); double subtract(double n1, double n2); double multiply(double n1, double n2); double divide(double n1, double n2); }
实现类分别调用对应的接口AddService,DivideService,MultiplyService,SubtractService
在CalculatorServiceImpl中分别调用对应的接口
public class CalculatorServiceImpl implements CalculatorService { private AddService addService; private SubtractService subtractService; private MultiplyService multiplyService; private DivideService divideService; @Reference public void setAddService(AddService addService) { this.addService = addService; } @Reference public void setSubtractService(SubtractService subtractService) { this.subtractService = subtractService; } @Reference public void setDivideService(DivideService divideService) { this.divideService = divideService; } @Reference public void setMultiplyService(MultiplyService multiplyService) { this.multiplyService = multiplyService; } public double add(double n1, double n2) { return addService.add(n1, n2); } public double subtract(double n1, double n2) { return subtractService.subtract(n1, n2); } public double multiply(double n1, double n2) { return multiplyService.multiply(n1, n2); } public double divide(double n1, double n2) { return divideService.divide(n1, n2); } }
通过@Reference进行注入,看一下每个接口的功能定义
AddService
public interface AddService { double add(double n1, double n2); }
AddServiceImpl
public class AddServiceImpl implements AddService { public double add(double n1, double n2) { Logger logger = Logger.getLogger("calculator"); logger.log(Level.FINEST, "Adding " + n1 + " and " + n2); return n1 + n2; } }
DivideService
public interface DivideService { double divide(double n1, double n2); }
DivideServiceImpl
public class DivideServiceImpl implements DivideService { public double divide(double n1, double n2) { Logger logger = Logger.getLogger("calculator"); logger.log(Level.FINEST, "Dividing " + n1 + " with " + n2); return n1 / n2; } }
MultiplyService
public interface MultiplyService { double multiply(double n1, double n2); }
MultiplyServiceImpl
public class MultiplyServiceImpl implements MultiplyService { public double multiply(double n1, double n2) { Logger logger = Logger.getLogger("calculator"); logger.log(Level.FINEST, "Multiplying " + n1 + " with " + n2); return n1 * n2; } }
SubtractService
public interface SubtractService { double subtract(double n1, double n2); }
SubtractServiceImpl
public class SubtractServiceImpl implements SubtractService { public double subtract(double n1, double n2) { Logger logger = Logger.getLogger("calculator"); logger.log(Level.FINEST, "Subtracting " + n1 + " from " + n2); return n1 - n2; } }
看客户端调用的代码
SCANodeFactory factory = SCANodeFactory.newInstance(); SCANode node = factory.createSCANodeFromClassLoader("Calculator.composite", CalculatorClient.class.getClassLoader()); node.start(); CalculatorService calculatorService = ((SCAClient)node).getService(CalculatorService.class, "CalculatorServiceComponent"); // Calculate System.out.println("3 + 2=" + calculatorService.add(3, 2)); System.out.println("3 - 2=" + calculatorService.subtract(3, 2)); System.out.println("3 * 2=" + calculatorService.multiply(3, 2)); System.out.println("3 / 2=" + calculatorService.divide(3, 2)); node.stop();
程序中读取Calculator.composite配置文件,这个是核心配置文件实现的功能是对外发布服务
再看一下配置文件中的定义
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0" targetNamespace="http://sample" xmlns:sample="http://sample" name="Calculator"> <component name="CalculatorServiceComponent"> <implementation.java class="calculator.CalculatorServiceImpl"/> <reference name="addService" target="AddServiceComponent" /> <reference name="subtractService" target="SubtractServiceComponent" /> <reference name="multiplyService" target="MultiplyServiceComponent" /> <reference name="divideService" target="DivideServiceComponent" /> </component> <component name="AddServiceComponent"> <implementation.java class="calculator.AddServiceImpl"/> </component> <component name="SubtractServiceComponent"> <implementation.java class="calculator.SubtractServiceImpl"/> </component> <component name="MultiplyServiceComponent"> <implementation.java class="calculator.MultiplyServiceImpl"/> </component> <component name="DivideServiceComponent"> <implementation.java class="calculator.DivideServiceImpl"/> </component> </composite>
发布的服务名为CalculatorServiceComponent
通过客户端的调用程序可以找到对应的服务名
CalculatorService calculatorService = ((SCAClient)node).getService(CalculatorService.class, "CalculatorServiceComponent");
然后调用相应的方法
程序执行结果如下:
2011-10-31 15:44:14 org.apache.tuscany.sca.node.impl.NodeImpl <init> 信息: Creating node: Calculator.composite 2011-10-31 15:44:16 org.apache.tuscany.sca.node.impl.NodeImpl configureNode 信息: Loading contribution: file:/D:/Java/workspace/sca/calculator/target/classes/ 2011-10-31 15:44:18 org.apache.tuscany.sca.node.impl.NodeImpl start 信息: Starting node: Calculator.composite 3 + 2=5.0 2011-10-31 15:44:18 org.apache.tuscany.sca.node.impl.NodeImpl stop 信息: Stopping node: Calculator.composite 3 - 2=1.0 3 * 2=6.0 3 / 2=1.5
也可以使用CORBA方式调用远端的实现,对应的服务端的配置,寻找本地的5080端口发布的服务
<component name="CalculatorServiceComponent"> <implementation.java class="calculator.CalculatorServiceImpl"/> <reference name="addService"> <tuscany:binding.corba uri="corbaname::localhost:5080#CalculatorCORBAService"/> </reference> <reference name="subtractService"> <tuscany:binding.corba uri="corbaname::localhost:5080#CalculatorCORBAService"/> </reference> <reference name="multiplyService"> <tuscany:binding.corba uri="corbaname::localhost:5080#CalculatorCORBAService"/> </reference> <reference name="divideService"> <tuscany:binding.corba uri="corbaname::localhost:5080#CalculatorCORBAService"/> </reference> </component>
测试用例中的代码实现如下:
public class CalculatorCORBAReferenceTestCase extends TestCase { private SCADomain scaDomain; private CalculatorService calculatorService; private TransientNameServer server; private void bindObject(String name, org.omg.CORBA.Object object) throws Exception { ORB orb = server.getORB(); org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); NamingContext ncRef = NamingContextHelper.narrow(objRef); NameComponent nc = new NameComponent(name, ""); NameComponent path[] = {nc}; ncRef.rebind(path, object); } @BeforeClass protected void setUp() throws Exception { // create name service server = new TransientNameServer("localhost", 5080, TransientNameService.DEFAULT_SERVICE_NAME); Thread t = server.start(); if (t == null) { Assert.fail("The naming server cannot be started"); } else { // create CORBA object which will be accessible by SCA CORBA binding bindObject("CalculatorCORBAService", new CalculatorCORBAServant()); scaDomain = SCADomain.newInstance("CalculatorCORBAReference.composite"); calculatorService = scaDomain.getService(CalculatorService.class, "CalculatorServiceComponent"); } } @AfterClass protected void tearDown() throws Exception { scaDomain.close(); server.stop(); } @Test public void testCalculator() throws Exception { assertEquals(5.0, calculatorService.add(3, 2)); assertEquals(1.0, calculatorService.subtract(3, 2)); assertEquals(6.0, calculatorService.multiply(3, 2)); assertEquals(1.5, calculatorService.divide(3, 2)); } }
服务是SOA的核心,它们代表了那些可以被结合在一起成为应用程序或业务流程的可工作,可重用的代码单元。
OSGI明确地把Java作为目标平台,提供用于创建组件的模块化框架,以及用来运行这些组件的运行时容器。OSGI本身并不提供可直接用于SOA服务所需的功能特性。
利用SCA,你可以用不同的编程语言构建功能单元或组件,然后将他们通过SOAP、JMS、RMI、REST或其它协议暴露为服务。
不仅如此,这些组件可以在内部被连在一起形成到时候高级别的服务或组合。服务可以以分布式的方式运行,并作为虚拟云来管理。