`

Java实现简易RPC框架(二)

 
阅读更多

 

上一遍blog我们已经说过了RPC的相关知识,接下来我们利用socket来实现RPC。

一、利用socket、动态代理实现RPC

参考阿里梁飞同学网上的例子,并调整单服务多线程模式,首先是框架代码

package org.bird.rpc;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
/**
 * RPC框架
 * @author liangjf
 *
 */
public class RpcFramework {
	static ServerSocket server = null;
	static Map<String,Object> serviceMap = new HashMap<String,Object>();
	/** 
     * 暴露服务 
	 * @param <C>
     *  
     * @param service 服务实现 
     * @param port 服务端口 
     * @throws Exception 
     */  
    public static <C> void export(final Object service, final int port) throws Exception {  
        if (service == null) { 
            throw new IllegalArgumentException("service instance == null"); 
        }
        if (port <= 0 || port > 65535) {
        	throw new IllegalArgumentException("Invalid port " + port);  
        }
        System.out.println("Export service " + service.getClass().getName() + " on port " + port);  
        
        if(server == null) {
        	server = new ServerSocket(port);
        }else if(server.getLocalPort() != port) {
        	server = new ServerSocket(port);
        }
        Class<Object>[] classs = (Class<Object>[]) service.getClass().getInterfaces();
        for(Class<Object> c : classs){
        	serviceMap.put(c.getName() + "|" + port, service);
        }
       
        new Thread(new Runnable(){//创建后台线程进行socket监听
			public void run() {
				while(true) {
				try {
					final Socket socket = server.accept(); 
	                        try {  
	                            try {  
	                                ObjectInputStream input = new ObjectInputStream(socket.getInputStream());  
	                                try { 
	                                	String interfaceName = input.readUTF();//客户端调用的接口
	                                    String methodName = input.readUTF();//service是服务器端提供服务的对象,但是,要通过获取到的调用方法的名称,参数类型,以及参数来选择对象的方法,并调用。获得方法的名称  
	                                    Class<?>[] parameterTypes = (Class<?>[])input.readObject();//获得参数的类型  
	                                    Object[] arguments = (Object[])input.readObject();//获得参数  
	                                    
	                                    Object remoter = RpcFramework.getService(interfaceName + "|" + port);
	                                    ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());  
	                                    try {  
	                                        Method method = remoter.getClass().getMethod(methodName, parameterTypes);//通过反射机制获得方法  
	                                        Object result = method.invoke(remoter, arguments);//通过反射机制获得类的方法,并调用这个方法  
	                                        output.writeObject(result);//将结果发送  
	                                    } catch (Throwable t) {  
	                                        output.writeObject(t);  
	                                    } finally {  
	                                        output.close();  
	                                    }  
	                                } finally {  
	                                    input.close();  
	                                }  
	                            } finally {  
	                                socket.close();  
	                            }  
	                        } catch (Exception e) {  
	                            e.printStackTrace();  
	                        }    
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			}
        	
        }).start(); 
    } 
    
    /** 
     * 引用服务 
     *  
     * @param <T> 接口泛型 
     * @param interfaceClass 接口类型 
     * @param host 服务器主机名 
     * @param port 服务器端口 
     * @return 远程服务 
     * @throws Exception 
     *///原理是通过代理,获得服务器端接口的一个“代理”的对象。对这个对象的所有操作都会调用invoke函数,在invoke函数中,是将被调用的函数名,参数列表和参数发送到服务器,并接收服务器处理的结果  
    @SuppressWarnings("unchecked")  
    public static <T> T refer(final Class<T> interfaceClass, final String host, final int port) throws Exception {  
        if (interfaceClass == null) {  
            throw new IllegalArgumentException("Interface class == null");  
        }
        if (! interfaceClass.isInterface()) { 
            throw new IllegalArgumentException("The " + interfaceClass.getName() + " must be interface class!");  
        }
        if (host == null || host.length() == 0) {
            throw new IllegalArgumentException("Host == null!");  
        }
        if (port <= 0 || port > 65535) {
            throw new IllegalArgumentException("Invalid port " + port);  
        }
        System.out.println("Get remote service " + interfaceClass.getName() + " from server " + host + ":" + port);  
        return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[] {interfaceClass}, new InvocationHandler() {//jdk动态代理,内部类 
            public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable {  
                Socket socket = new Socket(host, port);  
                try {  
                    ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());  
                    try {
                    	output.writeUTF(interfaceClass.getName());
                        output.writeUTF(method.getName());  
                        output.writeObject(method.getParameterTypes());  
                        output.writeObject(arguments);
                        ObjectInputStream input = new ObjectInputStream(socket.getInputStream());  
                        try {  
                            Object result = input.readObject();  
                            if (result instanceof Throwable) {  
                                throw (Throwable) result;  
                            }  
                            return result;  
                        } finally {  
                            input.close();  
                        }  
                    } finally {  
                        output.close();  
                    }  
                } finally {  
                    socket.close();  
                }  
            }  
        });  
    } 
    
    private static Object getService(String name) {
    	return serviceMap.get(name);
    }
}

 接着写两个需要暴露的服务接口

package org.bird.rpc;

/**
 * 服务接口
 * @author liangjf
 *
 */
public interface HelloService {
	
	String hello(String name);
}

 

package org.bird.rpc;
/**
 * 服务接口
 * @author liangjf
 *
 */
public interface GoodByeService {

	public String sayGoodBye(String name);
}

 实现服务类

package org.bird.rpc.impl;

import org.bird.rpc.HelloService;

public class HelloServiceImpl implements HelloService {
	
	public String hello(String name) {
		return "Hello " + name;
	}
}

 

package org.bird.rpc.impl;

import org.bird.rpc.GoodByeService;

public class GoodByeServiceImpl implements GoodByeService {

	public String sayGoodBye(String name) {
		return "Good Bye " + name;
	}
}

 接着写一个服务器测试类

package org.bird.rpc;

import org.bird.rpc.impl.GoodByeServiceImpl;
import org.bird.rpc.impl.HelloServiceImpl;
/**
 * 服务器
 * @author liangjf
 *
 */
public class Service {
	
	public  static void main(String[] args) throws Exception {
		HelloService helloService = new HelloServiceImpl();
		GoodByeService goodbyeService = new GoodByeServiceImpl();
		RpcFramework.export(helloService, Util.SP);
		RpcFramework.export(goodbyeService, Util.SP);
	}
}

 最后写一个远程客户端测试类

package org.bird.rpc;

/**
 * 客户端
 * @author liangjf
 *
 */
public class Client {

	/**
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		 HelloService service = RpcFramework.refer(HelloService.class,Util.SIP, Util.SP);    
		 for (int i = 0; i < 5; i++) {    
			 String hello = service.hello("World" + i);    
			 System.out.println(hello);    
			 Thread.sleep(2000);    
		 }  
	     GoodByeService goodbyeService = RpcFramework.refer(GoodByeService.class, Util.SIP, Util.SP);   
	     for(int i = 0 ; i < 5; i++) {
	    	 String goodbye = goodbyeService.sayGoodBye("ljf" + i);
	    	 System.out.println(goodbye);
	    	 Thread.sleep(2000);
	     }
	}

}

 IP跟端口辅助类

package org.bird.rpc;

public class Util {
	static String SIP = "127.0.0.1";
	static int SP = 8888;
}

 1、首先将RpcFramework、HelloService、GoodByeService、HelloServiceImpl、GoodByeServiceImpl、Service、Util这些类一起打包成可运行的server.jar;将RpcFramework、HelloService、GoodByeService、Client、Util这些类一起打包成两个可运行的client1.jar、client2.jar。

 

2、然后在命令行模式下通过java -jar server.jar命令启动server端

 3、再打开一个命令行窗口启动客户端client1


 我们再看看server端的变化

 4、另打开一个命令行窗口启动客户端client2

 再看看服务器端

从上面的测试结果来看我们只需要将接口暴露给远程客户端就可以进行远程RPC调用了,就像本地调用一样透明简单。主要实现原理是通过JDK动态代理动态生成代理实例。

  • 大小: 31.2 KB
  • 大小: 2.9 KB
  • 大小: 6 KB
  • 大小: 9.2 KB
  • 大小: 6.1 KB
  • 大小: 18.1 KB
分享到:
评论

相关推荐

    基于Java的简易RPC框架.zip

    基于Java的简易RPC框架 项目简介 本项目是一个简易的RPC(远程过程调用)框架,旨在通过模拟实现一个基本的RPC调用流程,帮助理解RPC的核心概念和实现原理。服务端采用Tomcat服务器,消费端使用HTTP协议发送网络...

    Java rpc框架简易版,类似dubbo分布式实现 (纯socket实现).zip

    本项目提供了一个简易版的Java RPC框架实现,旨在模仿著名的Dubbo框架,但采用了更基础的Socket通信方式进行分布式服务的搭建。以下是这个项目的核心知识点: 1. **RPC原理**:RPC使得客户端可以像调用本地方法一样...

    基于Java语言的简易RPC框架设计源码

    该项目为基于Java语言的简易RPC框架设计源码,包含66个文件,其中包括51个Java源文件、5个XML配置文件、3个序列化工具类、2个Markdown文件、2个属性配置文件以及1个Git忽略文件和1个注册中心配置文件。此框架适用于...

    基于Java实现一个简易的RPC框架【100012743】

    在这个基于Java实现的简易RPC框架项目中,我们将深入探讨如何构建这样一个框架,并实现对`printf`函数的远程调用。 首先,我们要理解RPC的基本原理。RPC使得客户端可以像调用本地方法一样调用远程服务器上的方法,...

    基于Java和Vert.x的简易RPC框架设计源码

    该项目是一个基于Java和Vert.x技术的简易RPC框架设计源码,共包含60个文件,主要由45个Java源文件、9个XML配置文件以及少量其他类型文件构成。该框架旨在提供一种高效、简洁的远程过程调用解决方案,适用于需要跨...

    Java rpc框架简易版,类似dubbo分布式实现 (纯socket实现)

    简介 demo-rpc(标准maven工程) 使用纯Java socket及简单多线程技术,不依赖任何第三方库类,实现简单实现类似dubbo的rpc调用。仅用于学习了解rpc调用过程, 实现略显简单,只体现rpc调用的关键步骤,存在很多优化细节,...

    guide-rpc-framework:由Netty + Kyro + Zookeeper实现的自定义RPC框架。(基于Netty + Kyro + Zookeeper实现的自定义RPC框架-附加详细实现过程和相关教程。)

    guide 目前只实现了RPC框架最基本的功能,一些可优化点都在下面提到了,有兴趣的小伙伴可以自我完善。 通过这个简易的轮子,你可以学到RPC的替代原理和原理以及各种Java编码实践的运用。 你甚至可以把当做你的毕设/...

    基于Netty+Kyro+Zookeeper的RPC框架.zip

    # 基于Netty+Kyro+Zookeeper的RPC框架 [中文](./README.md)|English ## 前言 通过这个简易的轮子,你可以学到 RPC 的底层原理及原理以及各种 Java 编码实践的运用。 ## 介绍 由于 Guide哥自身精力和能力...

    Netty4.1实战-手写RPC框架.pdf

    本文档将通过一系列章节详细介绍如何基于Netty 4.1版本实现一个简易的RPC框架。 #### 二、基础知识概述 ##### 2.1 RPC概念 - **定义**:RPC(Remote Procedure Call Protocol)即远程过程调用协议,它允许程序...

    分布式代码rpc.rar_DEMO_caf 分布式_herselfcz9_java f4框架_分布式

    在这个Java简易RPC框架中,"f4框架"可能是框架的一个组成部分,可能是用于序列化、网络通信或者服务治理的组件。"caf_分布式 herselfcz9"这部分标签信息可能是指框架的作者或版本,"caf"可能是一个简写或代号,...

    xmljava系统源码-handwriting:开源框架之手写系列,主要手写了springmvc,mybatis,rpc框架的实现,目前是跟着

    xml java系统源码 handwriting ...使用Java默认的序列化以及传统Socket通信实现简易的rpc框架 hw-mybatis 实现了mybatis的主要的核心功能,目前在xml解析以及查询返回值这些地方采用硬编码实现 待续中...

    jim-framework:一些公共组件及学习应用:RPC统一配置中心基于注解的分布式锁dubbo请求级缓存调用链追踪RabbitMQElasticsearchzookeeperSping boot

    过滤器机制简易RPC框架-客户端限流配置简易RPC框架-上下文简易RPC框架-代理简易RPC框架-熔断降级机制简易RPC框架-SPI熔断降级实现影响上下文机制,后续更新解决基于注解的锁Spring boot实践WEBValidator (未同步...

    rpc-framework:一个rpc框架演示

    rpc框架前言学习javaGuide,自己动手造个轮子,通过这个简易的轮子,可以学到RPC的扭曲原理和原理以及各种Java编码实践的运用。介绍是一种基于Netty + Kyro + Zookeeper实现的RPC框架。设计思路一个基本的RPC框架...

    mini-rpc:一个简易版 RPC 框架

    Mini RPC 项目架构 RPC 框架包含三个最重要的组件,分别是客户端、服务端和注册中心。在一次 RPC 调用流程中,这三个组件是这样交互的: 服务端在启动后,会将它提供的服务列表发布到注册中心,客户端向注册中心订阅...

    zrpc:简易的rpc框架

    zrpc是一个针对Java开发的轻量级RPC框架,旨在简化服务间的通信,提高系统的可扩展性和解耦性。 在zrpc框架中,主要涉及以下几个核心概念和技术点: 1. **服务提供者(Service Provider)**:服务提供者是拥有特定...

    java开源包4

    nfs-rpc是一个集成了各种知名通信框架的高性能RPC框架,目前其最好的性能为在采用grizzly作为通信框架,采用pb作为序列化/反序列化时,tps为168k次/秒。 其支持的功能主要为: 1、透明的调用远端服务器提供的功能...

    guide-rpc-framework:A custom RPC framework implemented by Netty+Kyro+Zookeeper.(一款基于 Netty+Kyro+Zookeeper 实现的自定义 RPC 框架-附详细实现过程和相关教程。)

    通过这个简易的轮子,你可以学到 RPC 的底层原理和原理以及各种 Java 编码实践的运用。 你甚至可以把 当做你的毕设/项目经验的选择,这是非常不错!对比其他求职者的项目经验都是各种系统,造轮子肯定是更加能赢得...

    区块链的基础功能简易版Java实现

    它使用 SpringBoot + Tio 网络框架实现,是一个非常好的区块链学习项目,目前只实现了 POW 共识算法,如果要用于生产项目需要根据自己的项目需求修改共识。 blockj-base 基础公共的工具包,如加密,区块,消息等...

    java开源包3

    nfs-rpc是一个集成了各种知名通信框架的高性能RPC框架,目前其最好的性能为在采用grizzly作为通信框架,采用pb作为序列化/反序列化时,tps为168k次/秒。 其支持的功能主要为: 1、透明的调用远端服务器提供的功能...

    java开源包6

    nfs-rpc是一个集成了各种知名通信框架的高性能RPC框架,目前其最好的性能为在采用grizzly作为通信框架,采用pb作为序列化/反序列化时,tps为168k次/秒。 其支持的功能主要为: 1、透明的调用远端服务器提供的功能...

Global site tag (gtag.js) - Google Analytics