用反射、代理、socket和zookeeper模拟dubbo远程调用接口(RPC)

实现一个简单的远程调用,需要四个项目,如下
在这里插入图片描述
api提供接口,service提供接口的实现,provider和consumer分别是提供者和消费者。

同时还需要一个zookeeper作为注册中心

连接流程图

具体思路:

provider启动后,将服务信息注册到zookeeper,同时开启socker监听,(这里的provider是作为socket中的服务端)。启动consumer,consumer启动后,立即从注册中心获取所需的服务信息(服务信息指提供者的地址和端口号,因为接下来要使用它们进行socket连接),然后使用获取到的服务信息,建立socket连接,得到返回的结果。

实现细节:

api模块
在这里插入图片描述
pom依赖

<dependencies>
		<!-- zkclient 用于与zookeeper建立连接 -->
		<dependency>
			<groupId>com.101tec</groupId>
			<artifactId>zkclient</artifactId>
			<version>0.11</version>
		</dependency>
	</dependencies>

Request封装的是请求信息,由consumer发送给provider,provider根据请求信息,通过反射找到具体的方法,并执行方法,返回结果给consumer

//因为Request类要通过socket传递,所以要实现序列化接口
public class Request implements Serializable {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1364252361112203421L;
	/**
	 * 接口名称
	 */
	private String interfaceName;
	/**
	 * 方法名称
	 */
	private String methodName;
	/**
	 * 参数
	 */
	private Object[] args;
	public String getInterfaceName() {
		return interfaceName;
	}
	public void setInterfaceName(String interfaceName) {
		this.interfaceName = interfaceName;
	}
	public String getMethodName() {
		return methodName;
	}
	public void setMethodName(String methodName) {
		this.methodName = methodName;
	}
	public Object[] getArgs() {
		return args;
	}
	public void setArgs(Object[] args) {
		this.args = args;
	}
	@Override
	public String toString() {
		return "Request [interfaceName=" + interfaceName + ", methodName=" + methodName + ", args="
				+ Arrays.toString(args) + "]";
	}
	public Request(String interfaceName, String methodName, Object[] args) {
		super();
		this.interfaceName = interfaceName;
		this.methodName = methodName;
		this.args = args;
	}
	public Request() {
		super();
		// TODO Auto-generated constructor stub
	}
	
	
}

这里的AddService就是服务接口,其中只写了一个简单的add方法

public interface AddService {

	/**
	 * 
	* @Title: add  
	* @Description: TODO 
	* @param @param a
	* @param @param b
	* @param @return  
	* @return int
	* @throws
	 */
	int add(Integer a,Integer b);
	
}

ProxyUtils,consumer从此类中获取一个代理类,请求的封装,发出,和接收都由代理类完成

public class ProxyUtils {
	
	// 获取一个代理类,由代理类封装请求信息,发送请求,接收请求,最终返回result结果
	public static <T> T getProxy(Class<T> interfaces) {
		@SuppressWarnings("unchecked")
		T proxy = (T)Proxy.newProxyInstance(ProxyUtils.class.getClassLoader(), new Class<?>[] {interfaces}, new InvocationHandler() {

			/**
			 * 代理对象核心方法,proxy代理类本身,method代理方法,args参数
			 */
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				if ("toString".equals(method.getName())) {
					return interfaces.getName()+"$proxy";
				}
				if ("equals".equals(method.getName())) {
					return Object.class.equals(this);
				}
				if ("hashCode".equals(method.getName())) {
					return Object.class.hashCode();
				}
				
				//封装请求信息
				Request request = new Request();
				request.setInterfaceName(interfaces.getName());
				request.setMethodName(method.getName());
				request.setArgs(args);
				
				//发送request
				Object result = null;
				Socket socket = null;
				
				InputStream inputStream = null;
				OutputStream outputStream = null;
				
				ObjectInputStream objectInputStream = null;
				ObjectOutputStream objectOutputStream = null;
				
				try {
					List<String> serviceList = ZkUtils.discover(interfaces.getName());
					String one = loadBalance(serviceList);
					String address = one.split(":")[0]; // 获取提供者地址
					Integer port = Integer.valueOf(one.split(":")[1]); // 获取提供者端口号
					socket = new Socket(address, port); //创建socket
					outputStream = socket.getOutputStream();
					objectOutputStream = new ObjectOutputStream(outputStream);
					objectOutputStream.writeObject(request); // 将对象写入对象流
					
					//接受提供者计算出的答案
					inputStream = socket.getInputStream();
					objectInputStream = new ObjectInputStream(inputStream);
					result = objectInputStream.readObject(); // 从对象流中读取结果
					System.out.println("收到"+port+"的回复:");
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					close(objectInputStream,inputStream,objectOutputStream,outputStream,socket);
				}
				
				return result;
			}
		});
		return proxy; // 返回结果给消费者
	}
	
	// 关闭资源
	public static void close(Closeable... closeables) {
		for (Closeable resource : closeables) {
			if(null != resource) {
				try {
					resource.close();
				} catch (IOException e) {
					e.printStackTrace();
				} finally {
					resource = null;
				}
			}
		}
	}
	
	// 实现简单的负载均衡
	public static String loadBalance(List<String> uris) {
		if(null == uris || uris.size() == 0) {
			return null;
		}
		Random random = new Random();
		int index = random.nextInt(uris.size());
		return uris.get(index);
	}

}

ZkUtils,封装了zookeeper的服务注册和服务发现

public class ZkUtils {
	
	//初始化zk
	private static ZkClient zkClient = null;
	private static final String SERVER_URL = "114.55.27.97:2181";
	
	static {
		zkClient = new ZkClient(SERVER_URL, 5000, 30000);
	}

	/**
	 * 
	* @Title: register  
	* @Description: 服务的注册 
	* @param @param serviceName
	* @param @param serviceAddress  
	* @return void
	* @throws
	 */
	public static void register(String serviceName,String serviceAddress) {
		if(null == serviceName || serviceName.equals("")) {
			throw new RuntimeException("服务名称不能为空");
		}
		if(!zkClient.exists("/"+serviceName)) {
			zkClient.createPersistent("/"+serviceName);
		}
		if(!zkClient.exists("/"+serviceName+"/"+serviceAddress)) {
			zkClient.createEphemeral("/"+serviceName+"/"+serviceAddress);
		}
		System.out.println(serviceName+"在"+SERVER_URL+"注册成功,节点为:"+"/"+serviceName+"/"+serviceAddress);
	}
	
	/**
	 * 
	* @Title: discover  
	* @Description: 服务的发现 
	* @param @param serviceName
	* @param @return  
	* @return List<String>
	* @throws
	 */
	public static List<String> discover(String serviceName){
		if(null == serviceName || serviceName.equals("")) {
			throw new RuntimeException("服务名称不能为空");
		}
		if(!zkClient.exists("/"+serviceName)) {
			return null;
		}
		List<String> childrens = zkClient.getChildren("/"+serviceName);
		return childrens;
	}
	
	public static void main1(String[] args) {
		register("憨批", "001");
		register("憨批", "002");
		register("憨批", "003");
		try {
			System.in.read();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public static void main(String[] args) {
		List<String> childrens = discover("憨批");
		System.out.println(childrens);
	}
}

service模块
在这里插入图片描述
pom依赖,依赖api

<dependencies>
  	<dependency>
  		<groupId>com.scaler7</groupId>
  		<artifactId>api</artifactId>
  		<version>0.0.1-SNAPSHOT</version>
  	</dependency>
  </dependencies>

没什么好说的,就是实现了api接口

public class AddServiceImpl implements AddService {

	@Override
	public int add(Integer a, Integer b) {
		return a+b;
	}

}

provider模块
在这里插入图片描述
pom依赖,它依赖api和service

<dependencies>
  	<dependency>
  		<groupId>com.scaler7</groupId>
  		<artifactId>api</artifactId>
  		<version>0.0.1-SNAPSHOT</version>
  	</dependency>
  	
  	<dependency>
  		<groupId>com.scaler7</groupId>
  		<artifactId>service</artifactId>
  		<version>0.0.1-SNAPSHOT</version>
  	</dependency>
  </dependencies>

Provider,提供者,启动后先去zookeeper注册,然后阻塞监听socket

public class Provider {

	public static void main(String[] args) throws Exception {
		Integer port = 6666;
		ServerSocket serverSocket = new ServerSocket(6666);

		// 提供者启动后就去zookeeper中注册
		ZkUtils.register(AddService.class.getName(), "localhost:"+port);

		System.out.println("提供者6666已启动!");

		// 循环监听
		listener(serverSocket);
	}

	private static void listener(ServerSocket serverSocket) {
		while (true) {
			// 等待消费者连接,这一步是阻塞的
			Socket accept = null;
			try {
				accept = serverSocket.accept();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			InputStream inputStream = null;
			ObjectInputStream objectInputStream = null;

			OutputStream outputStream = null;
			ObjectOutputStream objectOutputStream = null;

			try {
				inputStream = accept.getInputStream();
				objectInputStream = new ObjectInputStream(inputStream);
				Request request = (Request) objectInputStream.readObject();

				Object result = Invoker.invoker(request); // 通过代理类,得到结果

				// 将响应结果写入objectOutputStream,发送给消费者
				outputStream = accept.getOutputStream();
				objectOutputStream = new ObjectOutputStream(outputStream);
				objectOutputStream.writeObject(result);

			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				ProxyUtils.close(objectOutputStream, outputStream, objectInputStream, inputStream);
			}
		}
	}

}

Invoker类,调用此类中的invoker方法,即可通过反射找出接口的实现类中的具体方法,调用并返回结果

public class Invoker {
	
	public static Object invoker(Request question) {
		System.out.println("开始计算");
		String interfaceName = question.getInterfaceName();
		String methodName = question.getMethodName();
		Object[] args = question.getArgs();
		String className = getClassNameByInterfaceName(interfaceName);
		
		Object result = null;
		
		try {
			Class<?> clazz = Class.forName(className); // 实现类
			Object obj = clazz.newInstance(); // 实现类的对象
			Class<?>[] argsType = null; // 参数类型数组
			if(args != null && args.length != 0) {
				argsType = new Class<?>[args.length];
				for (int i = 0; i < args.length; i++) {
					argsType[i] = args[i].getClass();
				}
			}
			
			Method method = clazz.getMethod(methodName, argsType);
			result = method.invoke(obj, args);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}
	
	public static String getClassNameByInterfaceName(String interfaceName) {
		int endIndex = interfaceName.lastIndexOf('.'); // 获得最后一个 '.' 的索引
		StringBuilder sb = new StringBuilder(); 
		sb.append(interfaceName.subSequence(0, endIndex)); // com.scaler7.service
		sb.append(".impl."); // com.scaler7.service.impl.
		sb.append(interfaceName.substring(endIndex+1)); // com.scaler7.service.impl.AddService
		sb.append("Impl"); // com.scaler7.service.impl.AddServiceImpl
		return sb.toString();
	}

}

consumer模块

在这里插入图片描述
pom依赖

<dependencies>
  	<dependency>
  		<groupId>com.scaler7</groupId>
  		<artifactId>api</artifactId>
  		<version>0.0.1-SNAPSHOT</version>
  	</dependency>
  	
  	<dependency>
  		<groupId>com.rpc</groupId>
  		<artifactId>provider</artifactId>
  		<version>0.0.1-SNAPSHOT</version>
  	</dependency>
  </dependencies>

Consumer类

public class Consumer {
	public static void main(String[] args) throws IOException, ClassNotFoundException {
		
		//获取一个代理类
		AddService addService = ProxyUtils.getProxy(AddService.class);
		while(true) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			//调用add方法,实际是代理类将接口和方法封装入request,通过socker传给provider进行计算,返回结果
			Object result = addService.add(1, 2);
			System.out.println("答案是:"+result);
		}
		
	}
}

运行效果

启动三个provider
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
启动consumer,随机访问三个provider中的一个,模拟实现负载均衡
在这里插入图片描述
至此,一个简单的远程方法调用(RPC)就完成了

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值