发表于: 2017-09-20 20:10:03

2 913


今天做的事:

今天把志勇的那个计算器的例子跑通了,前人栽树后人乘凉,省了我不少事,然后大概研究了一下。


首先是昨天我以为需要把jar下下来手动依赖,但是今天仔细看了下志勇的日报,发现原来不是手动依赖的,当时看的太不仔细了

<!--https://mvnrepository.com/artifact/org.apache.tuscany.sca/tuscany-base-runtime-->
<dependency>
   <groupId>org.apache.tuscany.sca</groupId>
   <artifactId>tuscany-base-runtime</artifactId>
   <version>2.0.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tuscany.sca.aggregation/tuscany-binding-rmi-runtime-aggregation -->
<dependency>
   <groupId>org.apache.tuscany.sca.aggregation</groupId>
   <artifactId>tuscany-binding-rmi-runtime-aggregation</artifactId>
   <version>2.0.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tuscany.sca.aggregation/tuscany-binding-ws-runtime-axis2-aggregation -->
<dependency>
   <groupId>org.apache.tuscany.sca.aggregation</groupId>
   <artifactId>tuscany-binding-ws-runtime-axis2-aggregation</artifactId>
   <version>2.0.1</version>
</dependency>


然后不贴所有代码了,志勇都贴了,不浪费篇幅,这里就在前人的基础上分析一下吧。


首先我们要注意,看一下项目结构


按照我们之前的逻辑,加减乘除应该都放在计算器的接口里,实现类同理,但是为什么我们使用Tuscany的时候要这么设计呢?

这就是我昨天提到的组件的概念。其实我们调用的还是计算器的接口,即CalculatorService这个接口,但是,使用了其他各个组件的内容。

看一下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);
   }
}

我们可以看到,这这个实现类里面,我们调用了各个组件,然后使用了组件对外开放的方法。

这个和我们之前的想法不一样,我们之前会在这个计算器的实现类里直接实现相关的逻辑功能,然后会出现大量的代码量(当然这个比较简单,不是很明显),会严重干扰我们对于业务逻辑的把控,而将焦点放在如何实现某个逻辑功能上。

如果采用组件的形式,我们将耦合度降低,并且不用再关注细节,而只关注业务逻辑即可。


这就是我们为什么设置这么多的组件的接口的原因


接下来就是一个配置文件了

Calculator.composite

<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
          xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.1"
          targetNamespace="http://sample"
          name="Calculator">

   <component name="CalculatorServiceComponent">
       <implementation.java class="Impl.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="Impl.AddServiceImpl"/>
   </component>

   <component name="SubtractServiceComponent">
       <implementation.java class="Impl.SubtractServiceImpl"/>
   </component>

   <component name="MultiplyServiceComponent">
       <implementation.java class="Impl.MultiplyServiceImpl"/>
   </component>

   <component name="DivideServiceComponent">
       <implementation.java class="Impl.DivideServiceImpl"/>
   </component>

</composite>


这个文件的后缀名可能是第一次见,但是这个命名是必须的。

首先我尝试了将后缀名改为xml形式,报错。

接下来看内部文件内容

首先这几处报红是正常的,因为我们使用的文件头的缘故

<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
          xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.1"
          targetNamespace="http://sample"
          name="Calculator">

而,如果为了这个不爆红,我们换成另外一个文件头

<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
          targetNamespace="http://sample"
          xmlns:sample="http://sample"
          name="Calculator">

我们可以看到,这里之前报红的都变成了相应的标签内容了,但是运行起来是会报错的

Caused by: java.lang.ClassCastException: org.apache.tuscany.sca.assembly.impl.ExtensionImpl cannot be cast to org.apache.tuscany.sca.assembly.Composite


我们可以看到这里的意思是,这个扩展接口无法映射成为组件。说明我们使用的这个文件头是有问题的。


所以这个问题可能和IDEA是有关系的,就像我们之前遇到的Mapper的自动注入报红问题。


接下来我们考虑文件中的相关标签都是什么意思

首先是“容器构件

<composite>

然后就是相应的组件、

<component>

我们向放下这个,看一下这个模式


组合模式(Composite Pattern)

组合多个对象形成树形结构以表示具有“整体—部分”关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象) 的使用具有一致性,组合模式又可以称为“整体—部分”(Part-Whole)模式,它是一种对象结构型模式。


这里有张图

大概扫一眼就行了。


我们不考虑的太复杂,我们只需要知道,这个组合模式,将这些个组件变成了一种树形结构

记住这个概念,树形。


然后我们看看我们的配置文件

<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
          xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.1"
          targetNamespace="http://sample"
          name="Calculator">

   <component name="CalculatorServiceComponent">
       <implementation.java class="Impl.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="Impl.AddServiceImpl"/>
   </component>

   <component name="SubtractServiceComponent">
       <implementation.java class="Impl.SubtractServiceImpl"/>
   </component>

   <component name="MultiplyServiceComponent">
       <implementation.java class="Impl.MultiplyServiceImpl"/>
   </component>

   <component name="DivideServiceComponent">
       <implementation.java class="Impl.DivideServiceImpl"/>
   </component>

</composite>

我们看到我们共注册了5个组件,一个是计算器的,另外4个是加减乘除的

<reference>

这个代表引用其他组件的相应服务。

其中name属性是必须的,但是作用不详,target就是引用的服务组件

当我们注释掉任意一行的时候,就会报错。


接下来看一下如何调用组件

测试类

@Test
public void test()throws NoSuchServiceException {

Node node = NodeFactory.newInstance().createNode("Calculator.composite");
   node.start();

   CalculatorService calculatorService = 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();
}


我们先看一下关键的几句话

首先是

Node node = NodeFactory.newInstance().createNode("Calculator.composite");

这个节点指的是什么呢?

还记不记的我之前强调的,树形。

如果你知道树,就能够理解这个节点的用处。

通过配置文件构建一个节点。


node.start();

大概就是新建的意思,并且这个节点已经生效了。


CalculatorService calculatorService = node.getService(CalculatorService.class, "CalculatorServiceComponent");

通过之前构建的节点,然后在通过配置文件中的组件名,来获取相关的组件。


node.stop();

关闭节点。


到此为止,我们就将这个简单的Tuscany实现讲解完毕。


花了点时间,最后还是把Tuscany的rmi服务跑通了


马哥可以审核任务了


那就说说吧,话说Tuscany的rmi例子是真的少,这个框架不更新,确实没人用。


先看一下依赖的包

<!-- tuscany rmi -->
<dependency>
   <groupId>org.apache.tuscany.sca</groupId>
   <artifactId>tuscany-base-runtime</artifactId>
   <version>2.0.1</version>
</dependency>
<dependency>
   <groupId>org.apache.tuscany.sca</groupId>
   <artifactId>tuscany-binding-rmi-runtime</artifactId>
   <version>2.0.1</version>
   <scope>runtime</scope>
</dependency>
<dependency>
   <groupId>org.apache.tuscany.sca</groupId>
   <artifactId>tuscany-implementation-spring-runtime</artifactId>
   <version>2.0.1</version>
</dependency>


和之前的配置文件对比,其实就是加了一个标签

<service>

看一下改过的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
          xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.1"
          targetNamespace="http://sample"
          xmlns:sample="http://sample"
          xmlns:scallop="http://scallop/xmlns/sca/1.1"
          name="Calculator">

   <component name="CalculatorServiceComponent">
       <implementation.java class="Impl.CalculatorServiceImpl"/>

       <service name="CalculatorService">
           <interface.java interface="Inter.CalculatorService"/>
           <tuscany:binding.rmi uri="rmi://127.0.0.1:8199/CalculatorRMIService"/>
       </service>

       <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="Impl.AddServiceImpl"/>
   </component>

   <component name="SubtractServiceComponent">
       <implementation.java class="Impl.SubtractServiceImpl"/>
   </component>

   <component name="MultiplyServiceComponent">
       <implementation.java class="Impl.MultiplyServiceImpl"/>
   </component>

   <component name="DivideServiceComponent">
       <implementation.java class="Impl.DivideServiceImpl"/>
   </component>

</composite>


还是有报红问题,选择性眼瞎就行了

然后服务启动类

public static void main(String[] args) throws InterruptedException{

Node node = NodeFactory.newInstance().createNode("Calculator.composite");
   node.start();

   System.out.println("service启动");

}

然后客户端使用java的rmi调用就行了

@Test
public void test()throws MalformedURLException, RemoteException, NotBoundException {
CalculatorService Calculator = (CalculatorService) Naming.lookup("//127.0.0.1:8199/CalculatorRMIService");
   System. out.println("1+2结果: " + Calculator.add(1,2));
}


是不是觉得挺简单的?

确实挺简单的,但是有两个大坑!!!!!


第一,配置刚才的标签<service>

name名是有特定要求的,不是随便起的!!!!

我就在这栽了


第二,和第一有关系

就是你提供的那个远程服务组件是要加一个注解的


这个注解代表,你这个服务支持远程服务,并且这个注解所注释的服务组件接口就是你的之前<service>标签的name属性,不然就一直报你的远程服务未开启,缺少@Remotable注解的错误



远程调用




明天计划:开始为复盘做准备


问题:暂无


收获:Tuscany项目的搭建和使用。





返回列表 返回列表
评论

    分享到