架构设计(二)系统间通信管理

来源:互联网 发布:js split("") 编辑:程序博客网 时间:2024/06/06 02:19

系统间通信管理

一、基于消息方式实现系统间通信
1. Java自身技术: TCP/IP + BIO、TCP/IP + NIO、UDP/IP + BIO、 UDP/IP + NIO

  1. 开源项目: mina

二、 基于远程调用方式实现系统间通信
1. java自身技术: RMI 和 WebService

  1. 开源项目: Spring rmi 和 cxf

具体如下:

一、RMI
1、 rmi定义:
RMI(Remote Method Invocation, 远程方法调用),是jdk1.1中提供的JVM与JVM之间进行对象方法调用的技术框架的实现。通过RMI技术,某一个本地的JVM可以调用存在于另外一个JVM中的对象方法,就好像它仅仅是在调用本地JVM中的某个对象方法一样。JDK1.5版本中的RMI又进行了改进

2、 使用场景:
1). RMI是基于Java语言的,也就是说在RMI技术框架的描述中,只有server端和client端都使用java语言,才能使用RMI技术
2). RMI使用于两个系统都主要使用java语言进行构造,不需要考虑语言支持的情况,并且对两个java系统的通讯速度有要求的情况。
3). RMI是一个良好的、特殊的RPC实现:使用JRMP协议承载数据的描述,可以使用BIO和NIO两种IO通信模型,RMI框架可以在大规模集群系统中使用。

3、 框架的基本组成:
a. 定义RMI Remote接口
b. 实现这个RMI Remote接口
c. 生成Stub(桩)和Skeleton(骨架),这一步的具体操作视不同的JDK版本而有所不同(例如JDK1.5以后,Skeleton不需要手动)
d. 向”RMI注册表”注册在b步实现的RMI remote接口
e. 创建一个Remote客户端,通过java”命名服务”,在”RMI 注册表”所在的Ip Port中寻找注册好的RMI服务
f. Remote客户端像调用存在于本地JVM中对象那样,调用存在于远程JVM上的RMI接口

注意:
1). UnicastRemoteObject:代表RMI Server真实的服务提供者 将工作在 “本地JVM”上
2). Activatable: 代表RMI Server真实的服务提供者,不在 “本地JVM”上,而是通过”RMI Remote Server激活”技术,被序列化到”远程JVM”(即远程RMI注册表所在的JVM),并适时的被”远程JVM”加载运行
3). 两种JVM: RMI Server真实服务的JVM 和 RMI 注册表的JVM
4). Naming.rebind和Naming.bind区别: 前者如果注册表中已经有了这个服务,则之前的将被替换;而后者则抛出错误
5). registry.rebind和Naming.rebind区别: 前者是使用RMI注册表绑定,所以不需要写完整的RMI URL了;而后者是通过java的名称服务进行绑定,由于名称服务不止为RMI框架提供查询服务,所以在绑定时要书写完整的RMI URL。

4、 手动生成Stub类

rmic -classpath [项目class路径] [实现类]如: rmic -classpath E:\test\netty_frame com.rmi.RemoteServerImplrmiregistry 1099: 启动注册表JVM,需要将生成的stub文件和服务的接口文件放在classpath目录下面export CLASSPATH=$CLASSPATH:/home/test

5、 rmi框架总共有两种模式: UnicastRemoteObject和Activatable

6、 实现框架: spring rmi

7、 实例代码

// RemoteServerInterfacepublic interface RemoteServerInterface extends Remote{    /*     * RMI接口 负责查询目前已经注册的所有用户进程     */    public List<UserInfo> queryAllUserInfo(String str) throws RemoteException;    public List<UserInfo> queryAllUserInfo2(String str) throws RemoteException;}// RemoteServerImplpublic class RemoteServerImpl extends UnicastRemoteObject implements RemoteServerInterface {    /*     * 父类抛出异常,必须显示继承     */    public RemoteServerImpl() throws RemoteException {        super();    }    /**     *      */    private static final long serialVersionUID = -9099045958340509746L;    @Override    public List<UserInfo> queryAllUserInfo(String str) throws RemoteException {        System.out.println("str");        List<UserInfo> users = new ArrayList<UserInfo>();        UserInfo user1 = new UserInfo(0, "zhangsan");        UserInfo user2 = new UserInfo(1, "lisi");        users.add(user1);        users.add(user2);        return users;    }    @Override    public List<UserInfo> queryAllUserInfo2(String str) throws RemoteException {        System.out.println("str");        List<UserInfo> users = new ArrayList<UserInfo>();        UserInfo user1 = new UserInfo(2, "zhangsan2");        UserInfo user2 = new UserInfo(3, "lisi2");        users.add(user1);        users.add(user2);        return users;    }}// UserInfopublic class UserInfo implements Serializable {    /**     *      */    private static final long serialVersionUID = -3413210243305788156L;    private int id;    private String name;    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public UserInfo(int id, String name) {        super();        this.id = id;        this.name = name;    }    @Override    public String toString() {        return "UserInfo [id=" + id + ", name=" + name + "]";    }}// RemoteUnicastMainpublic class RemoteUnicastMain {    public static void main(String[] args) throws RemoteException {        // 目前得出结论: 注册表jvm和RMI Server JVM 必须在同一台机器上,跨机器好像不行        Registry registry2 = LocateRegistry.getRegistry("10.0.228.111", 9527);        Registry registry = LocateRegistry.createRegistry(9527);        RemoteServerImpl serverImpl = new RemoteServerImpl();        registry.rebind("queryAllUserInfo", serverImpl);    }}// RemoteClientpublic class RemoteClient {    public static void main(String[] args)             throws MalformedURLException, RemoteException, NotBoundException {        RemoteServerInterface remoteServerInterface =                 (RemoteServerInterface)Naming.lookup("rmi://127.0.0.1:9527/queryAllUserInfo");        List<UserInfo> queryAllUserInfo = remoteServerInterface.queryAllUserInfo("fuck");        for ( UserInfo user : queryAllUserInfo) {            System.out.println(user.toString());        }        System.out.println("-----------------------------------------");        List<UserInfo> queryAllUserInfo2 = remoteServerInterface.queryAllUserInfo2("fuck");        for ( UserInfo user : queryAllUserInfo2) {            System.out.println(user.toString());        }    }}// 以下这个是个人在理解的基础上所写的一个简单的例子public class Test1 {    public static void main(String[] args) {        Test1 t1 = new Test1();        // 服务端: 将接口实现类传递给注册表        Test2 t2 = new Test2(t1);        System.out.println(t2.m1("fuck"));    }    public String m1(String str) {        System.out.println(str);        return str + "_return";    }}// 相当于 接口的实现类的stubclass Test2 extends Test1 {    private Test1 t1;    public Test2(Test1 t1) {        this.t1 = t1;    }    @Override    public String m1(String str) {        try {            Method m1 = Test1.class.getMethod("m1", String.class);            return (String)m1.invoke(t1, str);        } catch (NoSuchMethodException | SecurityException e) {            e.printStackTrace();        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {            e.printStackTrace();        }         return null;    }}

二、 WebService
1、 定义:
WebService是一种跨语言的系统间交互标准。在这个标准中,对外提供功能的一方以http的方式提供服务,该服务采用WSDL(Web Service Description Language)描述,在这个文件中描述服务所使用的协议、所期望的参数、返回的参数格式等,调用端和服务端通过SOAP(Simple Object Access Protocol)协议来进行交互

2、 使用说明:
在java中使用WebService须首先将服务器端的服务根据描述生成相应的WSDL文件,并将应用及此WSDL文件放入http服务器中,借助java辅助工具根据WSDL文件生成客户端stub代码。此代码的作用是将产生的对象请求信息封装为标准的SOAP格式数据,并发送请求到服务器,服务器端在接收到SOAP格式数据时进行转换,反射调用相应的java类

3、 实例代码:
服务器端通过@WebService来标记对外暴露的WebService实现类,通过调用Endpoint.publish将此Webservice实现发布到指定的http地址上。
客户端通过wsimport来访问相应地址的WSDL文件,从而生成调用服务器端的辅助类,应用即可通过调用此类来实现远程调用了

注意:
1). WebService传输的数据协议采用SOAP, SOAP对于复杂的对象结构比较难支持,其好处是能够支持跨语言
2). 无论是采用RMI还是WebService,都封装了网络通信的细节,使用起来会比较简单,但如果想对通信细节做一些调优或控制,也会比较麻烦

4、 实现框架: cxf

// Businesspublic interface Business {    public String echo(String message);}// BusinessImplimport javax.jws.WebService;import javax.jws.soap.SOAPBinding;import javax.jws.soap.SOAPBinding.Style;import com.webservice.Business;@WebService(name="Business", serviceName="BusinessService", targetNamespace="http://WebService.chapter1.book/client")@SOAPBinding(style=Style.RPC)public class BusinessImpl implements Business {    @Override    public String echo(String message) {        if ("quit".equalsIgnoreCase(message)) {            System.out.println("Service will be shutdown");            System.exit(0);        }        System.out.println("Message from client: " + message);        return "Server response: " + message;    }}// BusinessMainpublic class BusinessMain {    public static void main(String[] args) {        Endpoint.publish("http://127.0.0.1:9527/BusinessService", new BusinessImpl());        System.out.println("Server has been started");    }}// 之后通过jdk的wsimport生成对应的stub// wsimport -keep http://127.0.0.1:9527/BusinessService?wsdl// 将生成的文件导入到项目中// BusinessClientpublic class BusinessClient {    public static void main(String[] args) {        BusinessService businessService = new BusinessService();        Business businessPort = businessService.getBusinessPort();        System.out.println(businessPort.echo("fuck you "));    }}
阅读全文
0 0
原创粉丝点击