Java实现远程服务生产与消费(RPC)的4种方法-RMI,WebService,HttpClient,RestTemplate

目录

本文将通过具体的远程服务发布与消费案例展示4种RPC远程调用方法.

一. 通过rmi实现远程服务的生产与消费

  • Java自身提供了java.rmi包, 方便开发者进行远程服务的部署与消费, 下面将通过具体案例进行讲解.

远程服务提供者实现.

创建rmi-provider项目(Maven)

  1. 创建UserService接口.
//将要发布的服务的接口
public interface UserService extends Remote {
    public String helloRmi(String name) throws RemoteException;
}
  1. 创建UserServiceImpl实现类
  • 注意, UserServiceImpl除了实现UserService接口外, 还要继承UnicastRemoteObject类, 你可以理解为它是一个发布出去供他人调用的类, 当UserServiceImpl实现了这个类后, UserServiceImpl就能被发布出去供别人调用.
//将要发布的服务的实现类
public class UserServiceImpl extends UnicastRemoteObject implements UserService {
    public UserServiceImpl() throws RemoteException {
        super();
    }

    public String helloRmi(String name) throws RemoteException {
        return "hello " + name;
    }
}
  1. 发布远程服务
public static void main(String[] args) {
    try {
        //完成远程服务的发布
        LocateRegistry.createRegistry(8888);//将远程服务发布在本地的8888端口
        String name = "rmi://localhost:8888/rmi";//发布的远程服务被访问的url
        UserService userService = new UserServiceImpl();//创建一个提供具体服务的远程对象
        Naming.bind(name, userService);//给远程服务绑定一个url
        System.out.println("--- 已发布rmi远程服务 ---");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

远程服务消费者实现

创建rmi-consumer项目

  1. rmi-provider项目种的UserService接口与UserServiceImpl实现类复制到本rmi-consumer项目中.(这一步可以进行优化解耦, 我们可以多创建一个rmi-resource项目, 让rmi-providerrmi-consumer共同依赖rmi-resource项目, 然后把资源文件比如远程服务所用到的UserService等放入rmi-resource项目中)
  2. 远程服务消费者对远程服务发起调用.
public static void main(String[] args) {
    try {
        //发布远程服务的访问url
        String name = "rmi://localhost:8888/rmi";
        //通过发布远程服务的url, 获取远程服务的代理对象
        UserService userService = (UserService) Naming.lookup(name);
        System.out.println("获得的远程服务的代理对象:" + userService.getClass().getName());
        String result = userService.helloRmi("rmi");//拿到远程方法调用的结果
        System.out.println("result: " + result);

    }catch (Exception e) {
        e.printStackTrace();
    }
}

//最后输出
获得的远程服务的代理对象:com.sun.proxy.$Proxy0
result: hello rmi
  • 通过最后的输出我们看到获得的远程服务对象是动态代理产生的.

 

二. 通过WebService实现远程服务的生产与消费

  • WebService协议是RPC的一种具体实现, 服务提供方和消费方通过http + xml进行通信.

远程服务提供者实现.

  1. 首先创建远程服务接口UserService及其实现类UserServiceImpl.
  • 注意, 使用WebService时需要对远程服务加上注解@WebService
@WebService
public interface UserService {
    public String sayHello(String name);
}

@WebService
public class UserServiceImpl implements UserService {
    @Override
    public String sayHello(String name) {
        return "hello " + name + "~";
    }
}
  1. 发布远程服务, 过程和rmi差不多, 需要提供远程服务的访问地址和具体的远程服务实现类, 使用Endpoint类的publish()方法进行发布, 这都是JDK封装好的.
public class WsProviderApp {
    public static void main(String[] args) {
        //发布的WebService的被访问地址
        String address = "http://localhost:9999/ws";
        //创建远程服务对象
        UserService userService = new UserServiceImpl();
        //发布服务
        Endpoint.publish(address, userService);
        System.out.println("远程服务已经发布...");
    }
}

查看远程服务文档wdsl

  • rmi不同的是, WebService发布后, 调用者可以通过查看它的文档对远程服务发起调用.
  • 查看的方法是在浏览器中输入远程服务的访问地址加上?wdsl, 比如本案例中是http://localhost:9999/ws?wsdl
  • 注意, 在客户端调用远程方法时需要用工具对wdsl文档进行解析, 并获得调用远程方法的工具类. 具体操作见下一段.

远程服务消费者实现.

  1. 首先根据文档获得调用远程服务的工具类, JDK已经为我们封装好了获取的工具, 它在bin目录下, 名字是wsimport
  2. 打开命令行, 在命令行中输入解析命令
wsimport -keep -d C:\githubRepositories\shopping\ws-consumer\src\main\java -p com.shenghao.client http://localhost:9999/ws?wsdl

解释:
1. wsimport 是命令的名字
2. -keep 用于保留生成的类, 如果没有该指令会只生成class文件
3. -d 后面接项目中存放这些工具类的包, 填绝对路径
4. -p 填wdsl文档的地址
watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 
5. 可以看到命令执行完后, 指定的包中出现一堆相关的类, 最直接调用到的类是UserServiceImplService. 下面演示对远程方法进行调用.

public static void main(String[] args) {
    //创建服务类对象
    UserServiceImplService service = new UserServiceImplService();
    //获得远程服务的代理对象
    UserServiceImpl userService = service.getUserServiceImplPort();
    System.out.println(userService.getClass().getName());
    //对远程服务对象的方法进行调用
    String result = userService.sayHello("炭烧生蚝");
    System.out.println(result);
}

//结果输出
com.sun.proxy.$Proxy32
hello 炭烧生蚝~

三. 通过HttpClient实现远程服务的生产与消费

  • 这里我们换一个案例进行演示. 假设现在有一套用户系统和一套订单系统, 要实现用户系统访问订单系统以获得某个用户的订单信息.

远程服务提供者实现

  • 提供远程服务的过程和响应web请求很相似, 只不过响应的不是<html>标签, 而是json字符串. 微信小程序前后端通信也是这个原理.
  1. 创建名为order-sys的Maven项目, 指定打包为war包.
点击这里查看pom.xml文件, 常规操作

<properties>
    <!-- spring 依赖 -->
    <spring.version>4.3.18.RELEASE</spring.version>
    <jstl.version>1.2</jstl.version>
    <servlet-api.version>2.5</servlet-api.version>
    <jsp-api.version>2.0</jsp-api.version>
    <jackson.version>2.9.0</jackson.version>
</properties>

<dependencies>
    <!-- jsp相关依赖 -->
    <!-- servlet依赖 -->
    <!-- jstl依赖 -->
    <dependency>
        <groupId>jstl</groupId>
        <artifactId>jstl</artifactId>
        <version>${jstl.version}</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>${servlet-api.version}</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jsp-api</artifactId>
        <version>${jsp-api.version}</version>
        <scope>provided</scope>
    </dependency>
    <!-- springmvc依赖-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>${jackson.version}</version>
    </dependency>
</dependencies>
<build>
    <finalName>order</finalName>
    <plugins>
        <!-- 配置Tomcat插件 -->
        <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <version>2.2</version>
            <configuration>
                <path>/order</path>
                <port>7070</port>
            </configuration>
        </plugin>

    </plugins>
</build></code></p>

 
2. 创建订单类

public class Order {
    private String id;
    private Double total;
    private String date;

    //get / set ...
}
对外提供服务, 发布时打包发布到Tomcat
@Controller
public class OrderController {
    /**
     * 接收http请求, 响应订单集合, 异步响应
     * 将list集合序列化为json串响应
     * @param uid
     * @return
     */
    @RequestMapping("/loadOrderList2")
    @ResponseBody
    public List<Order> loadOrderList2(String uid){
        System.out.println("uid: " + uid);

        //模拟订单数据
        Order o1 = new Order();
        o1.setId("111");
        o1.setTotal(333.33);
        o1.setDate("2019-4-29");

        Order o2 = new Order();
        o2.setId("222");
        o2.setTotal(444.44);
        o2.setDate("2019-5-29");

        Order o3 = new Order();
        o3.setId("333");
        o3.setTotal(555.55);
        o3.setDate("2019-6-29");

        List<Order> list = new ArrayList<>();
        list.add(o1);
        list.add(o2);
        list.add(o3);

        return list;
    }
}

远程服务消费者实现

在服务消费端使用HttpClient发送请求, 可以理解为模拟浏览器发送post/get请求. HttpClient为我们封装了拼接一个请求的细节, 使得发送一个请求变得容易.
public static void main(String[] args) throws IOException {
    //发送远程的http请求的地址
    String url = "http://localhost:7070/order/loadOrderList2";
    //创建HttpClient对象
    CloseableHttpClient client = HttpClients.createDefault();
    //创建HttpPost对象, 发送post请求
    HttpPost method = new HttpPost(url);
    //封装发送到服务提供者的参数
    NameValuePair id = new BasicNameValuePair("uid", "10001");
    List<NameValuePair> params = new ArrayList<>();
    params.add(id);
    //封装请求体数据
    method.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
    //发送具体的http请求
    HttpResponse response = client.execute(method);

    //获得服务提供者响应的具体数据
    HttpEntity entity = response.getEntity();
    //获得http的响应体
    InputStream is = entity.getContent();

    int len = 0;
    char[] buf = new char[1024];
    //使用字符流读
    InputStreamReader reader = new InputStreamReader(is);
    StringBuffer sb = new StringBuffer();
    while((len = reader.read(buf)) != -1){
        sb.append(String.valueOf(buf, 0, len));
    }
    System.out.println(sb);

    //将响应回来的json字符串解析为Order集合
    List<Order> list = JSON.parseArray(sb.toString(), Order.class);
    for(Order o : list){
        System.out.println(o.getId() + "\t" + o.getTotal() + "\t" + o.getDate());
    }
}

 

四. 通过spring提供的RestTemplate实现远程服务的生产与消费

通过一个红包系统和订单系统进行演示, 红包系统访问订单系统, 获得某个用户的订单信息, 派发红包. 订单系统继续沿用HttpClient中的订单系统, 通过访问loadOrderList2方法能返回一个订单集合Json字符串.

远程服务消费者实现.

@Controller
public class RedController {
    //注入由spring提供的RestTemplate对象
    @Autowired
    private RestTemplate restTemplate;
    /**
     * 发送远程的http请求, 消费http服务
     * 获得订单对象的集合
     */
    @RequestMapping("/loadOrderList3")
    @ResponseBody
    public List<ResponseEntity<Order[]>> loadOrderList3(String uid){
        //发送远程http请求的url
        String url = "http://localhost:7070/order/loadOrderList2";
        //发送到远程服务的参数
        MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
        params.add("uid", uid);

        //通过RestTemplate对象发送post请求
        ResponseEntity<Order[]> entitys = restTemplate.postForEntity(url, params, Order[].class);

        //查看响应的状态码
        System.out.println(entitys.getStatusCodeValue());

        //查看响应头
        HttpHeaders headMap = entitys.getHeaders();
        for(Map.Entry<String, List<String>> m : headMap.entrySet()){
            System.out.println(m.getKey() + ": " + m.getValue());
        }

        return Arrays.asList(entitys);
    }
}

原文地址:https://blog.51cto.com/u_14797091/2758889

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


1.使用ajax调用varxhr;functioninvoke(){if(window.ActiveXObject){xhr=newActiveXObject("Microsoft.XMLHTTP");}else{xhr=newXMLHttpRequest();}//指定请求地址varurl="http://127.0.0.1:7777/hello?wsdl";//
               好不容易把WebService服务器端搭建起来,我们还需要客户端程序也同样跑起来才能够进行和服务器端程序的通信: 在这篇文章里面,我会先自己写代码去实现调用WebService服务器端程序,接下来,通过IDEA配置的方式来调用WebService服务端: 首先,我写了一个W
1新建一个工程项目用来做服务端增加一个MyService1类文件packagecom.zns.ws;importjavax.jws.WebMethod;importjavax.jws.WebService;importjavax.xml.ws.Endpoint;@WebServicepublicclassMyService1{publicstaticvoidmain(String[]args){
packagecom.transsion.util;importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.PrintWriter;importjava.net.URL;importjava.net.URLConnection;importcom.alibaba.druid.util.Base64;importcom.tra
再生产wsdl文件时重写描述文件1usingSystem;2usingSystem.Collections.Generic;3usingSystem.Linq;4usingSystem.Web;5usingSystem.Web.Services.Description;67namespaceStrongSoftManage.Web.App8{9publicclassSoapExtens:SoapExtensi
一般情况下,使用eclipse自带的jax-ws生成webservice会自动生成2个类:ContractConnector.java packagecom.wonders.webservice.contract;importjava.text.DecimalFormat;importjava.text.ParseException;importjava.text.SimpleDateFormat;importjava.util.Date;i
一、WebService概述1.1什么是WebService 基于Web的服务:服务器端整出一些资源让客户端应用访问(获取数据) 一个跨语言、跨平台的规范(抽象)所谓跨编程语言和跨操作平台,就是说服务端程序采用java编写,客户端程序则可以采用其他编程语言编写,反之亦然!跨操作系统平台则是指服务
一、什么是CXF?    ApacheCXF=Celtix+Xfire,开始叫ApacheCeltiXfire,后来更名为ApacheCXF了,以下简称为CXF。ApacheCXF是一个开源的webServices框架,CXF帮助您构建和开发webServices,它支持多种协议,比如:SOAP1.1,1,2 XML/HTTP、RESTful或者CORBA。  
工具IDEA一、构建项目1、选择SpringInitializr2、填写项目信息3、勾选webService4、勾选Thymeleaf5、项目建立完成,启动类自动生成二、写个Controller启动服务。浏览器访问/hello接口。 
1.环境win764位,vs20102.新建一个asp.netweb应用程序(同上一篇)3.添加一个web引用,引用上一篇创建的服务。注意不是服务引用。如下图 
WebService之WSDL文件讲解   恩,我想说的是,是不是经常有人在开发的时候,特别是和第三方有接口的时候,走的是SOAP协议,然后用户给你一个WSDL文件,说按照上面的进行适配,嘿嘿,这个时候,要是你以前没有开发过,肯定会傻眼,那如果你想学习的话,就认真的看下面的讲解咯:一、WSDL概述  
在websrvice发布文件的webconfig中加入<httpRuntimemaxRequestLength="102400"/> <webServices>     <protocols>       <addname="HttpPost"/>       <addname="HttpGet"/>     </protocols>   
 代码比较简单,按照如下来操作即可,只是jar包有很多问题,比如找不到classnotFondspring、以及找不到xfile.xml、以及xfile.xml中的一个参数问题,以及2.0 spring。jar和spring1.6.2冲突问题,总之这个小demo报了一堆错误,其实都是jar的问题,为了让大家减少这方面的错误,所以我提供
 一、soapUI简介SOAP:   WebService通过Http协议发送请求和接收结果时,发送的请求内容和结果内容都采用XML格式封装,并增加了一些特定的HTTP消息头,以说明HTTP消息头的内容格式,这些特定的HTTP消息头和XML内容格式就是SOAP协议。SOAP提供了标准的RPC方法来调用WebService。 
参考,感谢https://blog.csdn.net/hj7jay/article/details/727224381.环境:win764位,jdk1.8.0_201 EclipseJavaEEIDEforWebDevelopers.Version:Mars.1Release(4.5.1)2.创建一个普通的java项目,名字是TheService在src目录下创建一个com.hyan.service包,在此包下创建
CXF实现RestfulWebService基础示例一、写在前面IDE:IDEA14JDK:1.7CXF:2.6.2示例来源:%CXF_HOME%\samples\jax_rs\basic发布方式:JAXRSServerFactoryBean的create()方法调用方式:URL的openStream()方法、HttpClient的executeMethod()方法二、服务端(Java项目)1.准备Jar包
封装helper类:classWebServiceHelper{///<summary>///1.get请求http方法///</summary>///<paramname="url">基础url</param>///<paramname="method">请求方法</param>///<paramnam
.net客户端调用java或.netwebservice进行soapheader验证最近项目中有业务需要跨平台调用web服务,客户端和服务器之间采用非对称加密来保证数据的安全性,webservice的安全验证基于soapheader。借此机会,顺便整理一下调用.netwebservice和javawebservice的验证方式,记录下来。
Node.jshttps://www.cnblogs.com/goldlong/p/8027997.htmlQQ音乐apihttps://juejin.im/post/5a35228e51882506a463b172#heading-11?tdsourcetag=s_pcqq_aiomsgGit把本地仓库上传到GitHbubhttps://blog.csdn.net/zamamiro/article/details/70172900git删除本地仓库https://blog.cs
转载自:孤傲苍狼 WebService学习总结(三)——使用JDK开发WebService一、WebService的开发手段使用Java开发WebService时可以使用以下两种开发手段1、 使用JDK开发(1.6及以上版本)-->详见:本文2、使用CXF框架开发-->详见:其他文章二、使用JDK开发WebServi