发表于: 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项目的搭建和使用。
评论