Java实现远程服务生产与消费(RPC)的4种方法-RMI,WebService,HttpClient,RestTemplate
2021/5/7 14:29:42
本文主要是介绍Java实现远程服务生产与消费(RPC)的4种方法-RMI,WebService,HttpClient,RestTemplate,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
目录-
一. 通过rmi实现远程服务的生产与消费
-
远程服务提供者实现.
- 创建rmi-provider项目(Maven)
-
远程服务消费者实现
- 创建rmi-consumer项目
-
远程服务提供者实现.
-
二. 通过WebService实现远程服务的生产与消费
- 远程服务提供者实现.
- 查看远程服务文档wdsl
- 远程服务消费者实现.
-
三. 通过HttpClient实现远程服务的生产与消费
- 远程服务提供者实现
- 远程服务消费者实现
-
四. 通过spring提供的RestTemplate实现远程服务的生产与消费
- 远程服务消费者实现.
本文将通过具体的远程服务发布与消费案例展示4种RPC远程调用方法.
一. 通过rmi实现远程服务的生产与消费
- Java自身提供了
java.rmi
包, 方便开发者进行远程服务的部署与消费, 下面将通过具体案例进行讲解.
远程服务提供者实现.
创建rmi-provider项目(Maven)
- 创建
UserService
接口.
//将要发布的服务的接口 public interface UserService extends Remote { public String helloRmi(String name) throws RemoteException; }
- 创建
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; } }
- 发布远程服务
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项目
- 把
rmi-provider
项目种的UserService
接口与UserServiceImpl
实现类复制到本rmi-consumer
项目中.(这一步可以进行优化解耦, 我们可以多创建一个rmi-resource
项目, 让rmi-provider
和rmi-consumer
共同依赖rmi-resource
项目, 然后把资源文件比如远程服务所用到的UserService
等放入rmi-resource
项目中) - 远程服务消费者对远程服务发起调用.
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
进行通信.
远程服务提供者实现.
- 首先创建远程服务接口
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 + "~"; } }
- 发布远程服务, 过程和
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文档进行解析, 并获得调用远程方法的工具类. 具体操作见下一段.
远程服务消费者实现.
- 首先根据文档获得调用远程服务的工具类, JDK已经为我们封装好了获取的工具, 它在
bin
目录下, 名字是wsimport
- 打开命令行, 在命令行中输入解析命令
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文档的地址
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
字符串. 微信小程序前后端通信也是这个原理.
- 创建名为
order-sys
的Maven项目, 指定打包为war
包.
<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); } }
这篇关于Java实现远程服务生产与消费(RPC)的4种方法-RMI,WebService,HttpClient,RestTemplate的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-09-28AI给的和自己写的Python代码,都无法改变输入框的内容,替换也不行
- 2024-09-27Sentinel配置限流资料:新手入门教程
- 2024-09-27Sentinel配置限流资料详解
- 2024-09-27Sentinel限流资料:新手入门教程
- 2024-09-26Sentinel限流资料入门详解
- 2024-09-26Springboot框架资料:初学者入门教程
- 2024-09-26Springboot框架资料详解:新手入门教程
- 2024-09-26Springboot企业级开发资料:新手入门指南
- 2024-09-26SpringBoot企业级开发资料新手指南
- 2024-09-26Springboot微服务资料入门教程