案例九 java实现RPC通信,即web服务器项目

一、RPC简介

RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议。它允许像调用本地服务一样调用远程服务。它可以有不同的实现方式。如RMI(远程方法调用)、Hessian、Http invoker等。另外,RPC是与语言无关的。

    RPC示意图

如上图所示,假设Computer1在调用sayHi()方法,对于Computer1而言调用sayHi()方法就像调用本地方法一样,调用 –>返回。但从后续调用可以看出Computer1调用的是Computer2中的sayHi()方法,RPC屏蔽了底层的实现细节,让调用者无需关注网络通信,数据传输等细节。

二、RPC框架的实现

    上面介绍了RPC的核心原理:RPC能够让本地应用简单、高效地调用服务器中的过程(服务)。它主要应用在分布式系统。如Hadoop中的IPC组件。但怎样实现一个RPC框架呢?

从下面几个方面思考,仅供参考:

1.通信模型:假设通信的为A机器与B机器,A与B之间有通信模型,在Java中一般基于BIO或NIO;。

2.过程(服务)定位:使用给定的通信方式,与确定IP与端口及方法名称确定具体的过程或方法;

3.远程代理对象:本地调用的方法(服务)其实是远程方法的本地代理,因此可能需要一个远程代理对象,对于Java而言,远程代理对象可以使用Java的动态对象实现,封装了调用远程方法调用;

4.序列化,将对象名称、方法名称、参数等对象信息进行网络传输需要转换成二进制传输,这里可能需要不同的序列化技术方案。如:protobuf,Arvo等。

三、Java实现RPC框架

1、实现技术方案

     下面使用比较原始的方案实现RPC框架,采用Socket通信、动态代理与反射与Java原生的序列化。

2、RPC框架架构

RPC架构分为三部分:

1)服务提供者,运行在服务器端,提供服务接口定义与服务实现类。

2)服务中心,运行在服务器端,负责将本地服务发布成远程服务,管理远程服务,提供给服务消费者使用。

3)服务消费者,运行在客户端,通过远程代理对象调用远程服务。

3、 具体实现

分层

dao              接口和接口实现类

service            服务器端

Util                工具

client            客户端

test                测试类

model            业务逻辑

user.java        

package ch09.model;

import java.io.Serializable;

public class User implements Serializable{
	private String userName;
	private String passWord;
	private String nickName;
	private int age;
	
	
	public User() {
		super();
	}
	public User(String userName, String passWord, String nickName, int age) {
		super();
		this.userName = userName;
		this.passWord = passWord;
		this.nickName = nickName;
		this.age = age;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getPassWord() {
		return passWord;
	}
	public void setPassWord(String passWord) {
		this.passWord = passWord;
	}
	public String getNickName() {
		return nickName;
	}
	public void setNickName(String nickName) {
		this.nickName = nickName;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "User [userName=" + userName + ", passWord=" + passWord + ", nickName=" + nickName + ", age=" + age
				+ "]";
	}
	
}

UserResult.java

package ch09.model;

import java.io.Serializable;

public class UserResult implements Serializable{
	//是否登录成功
	private boolean result;
	
	//描述信息
	private String dec;

	public boolean isResult() {
		return result;
	}

	public void setResult(boolean result) {
		this.result = result;
	}

	public String getDec() {
		return dec;
	}

	public void setDec(String dec) {
		this.dec = dec;
	}

	@Override
	public String toString() {
		return "UserResult [result=" + result + ", dec=" + dec + "]";
	}
	
	

}

Response.java

package ch09.model;

import java.io.Serializable;

/**
 * 得到返回数据
 * 1:返回状态码
 * 2:返回的结果   ----->userResult
 * 3:返回异常信息
 * @author Administrator
 *
 */
public class Response implements Serializable{
	private String status;
	private UserResult result;
	private Exception e;
	public String getStatus() {
		return status;
	}
	public void setStatus(String status) {
		this.status = status;
	}
	public UserResult getResult() {
		return result;
	}
	public void setResult(UserResult result) {
		this.result = result;
	}
	public Exception getE() {
		return e;
	}
	public void setE(Exception e) {
		this.e = e;
	}
	@Override
	public String toString() {
		return "Response [status=" + status + ", result=" + result + ", e=" + e + "]";
	}
	

}

Request.java

package ch09.model;

import java.io.Serializable;
import java.util.Arrays;

/**
 * 发送的请求
 * 1:类名
 * 2:方法名
 * 3:参数类型
 * 4:参数
 * @author Administrator
 *
 */
public class Request implements Serializable{
	private String className;
	private String methodName;
	private Class[] paramTypes;
	private Object[] paramValues;
	public String getClassName() {
		return className;
	}
	public void setClassName(String className) {
		this.className = className;
	}
	public String getMethodName() {
		return methodName;
	}
	public void setMethodName(String methodName) {
		this.methodName = methodName;
	}
	public Class[] getParamTypes() {
		return paramTypes;
	}
	public void setParamTypes(Class[] paramTypes) {
		this.paramTypes = paramTypes;
	}
	public Object[] getParamValues() {
		return paramValues;
	}
	public void setParamValues(Object[] paramValues) {
		this.paramValues = paramValues;
	}
	@Override
	public String toString() {
		return "Request [className=" + className + ", methodName=" + methodName + ", paramTypes="
				+ Arrays.toString(paramTypes) + ", paramValues=" + Arrays.toString(paramValues) + "]";
	}
	
	

}

UserService.java

package ch09.server;

import ch09.model.User;
import ch09.model.UserResult;

/**
 * 用户登录和注册
 * @author Administrator
 *
 */
public interface UserService {
	
	
	UserResult login(User user);
	
	UserResult register(User user);

}

UserServiceImpl.java

package ch09.server;

import ch09.dao.UserDao;
import ch09.dao.impl.UserDaoImpl;
import ch09.model.User;
import ch09.model.UserResult;
import ch09.server.UserService;

public class UserServiceImpl implements UserService{

	@Override
	public UserResult login(User user) {
		//保存返回数据的
		UserResult result = new UserResult();
		UserDao dao = new UserDaoImpl();
		//通过用户名从文件中取到的
		User userByName = dao.getUserByName(user.getUserName());
		if(userByName==null){//没有找到该用户
			result.setResult(false);
			result.setDec("没有该用户");
		}else{
			if(userByName.getPassWord().equals(user.getPassWord())){
				result.setResult(true);
				result.setDec("登录成功");
			}else{
				result.setResult(false);
				result.setDec("用户名密码不匹配");
			}
		}
		return result;
	}

	@Override
	public UserResult register(User user) {
		UserResult result = new UserResult();
		UserDao dao = new UserDaoImpl();
		User userByName = dao.getUserByName(user.getUserName());
		if(userByName==null){//没有人注册过这个名字
			if(dao.save(user)){
				result.setResult(true);
				result.setDec("注册成功");
			}else{
				result.setResult(false);
				result.setDec("未知异常,注册失败");
			}
		}else{
			result.setResult(false);
			result.setDec("名字被占用");
		}
		return result;
	}

}

Const.java

package ch09.util;


/**
 * 存放常量
 *
 */
public class Const {
	public static final String FILE_PATH = "E:\\data\\userMapFile.txt";

}

FileUtils.java

package ch09.util;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Map;

import ch09.model.User;

/**
 * 读取文件和保存文件
 * map
 * @author Administrator
 *
 */
public class FileUtiles {
	
	/**
	 * 保存对象到文件中
	 * @param map
	 */
	public static void saveMapToFile(Map map){
		try {
			ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(Const.FILE_PATH));
			oos.writeObject(map);
			oos.flush();
			oos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	/**
	 * 获取所有user    获取map
	 * @return
	 */
	public static Map getUserMapByFile(){
		try {
			ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Const.FILE_PATH));
			Object readObject = ois.readObject();
			Map map = (Map)readObject;
			return map;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
}

Server.java

package ch09;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;

import ch09.model.Request;
import ch09.model.Response;
import ch09.model.UserResult;

/**
 * 发布服务
 * @author Administrator
 *
 */
public class Server {
	public static void main(String[] args) {
		
		try {
			ServerSocket ssc = new ServerSocket(9999);
			while(true){
				//获取客户端的链接
				Response res = new Response();
				Socket accept = ssc.accept();
				ObjectInputStream ois = new ObjectInputStream(accept.getInputStream());
				//接收到对象
				Object readObject = ois.readObject();
				Request req = (Request)readObject;
				String className = req.getClassName();
				String methodName = req.getMethodName();
				Class[] paramTypes = req.getParamTypes();
				Object[] paramValues = req.getParamValues();
				
				//反射
				//获取class对象
				Class forName = Class.forName(className);
				//根据class进行实例化
				Object newInstance = forName.newInstance();
				//获取方法对象
				Method method = forName.getMethod(methodName, paramTypes);
				//执行方法
				Object invoke = method.invoke(newInstance, paramValues);
				UserResult result = (UserResult)invoke;
				
				res.setStatus("200");
				res.setResult(result);
				//得到输出流,把数据发送给客户端
				ObjectOutputStream oos = new ObjectOutputStream(accept.getOutputStream());
				//把数据发送出去
				oos.writeObject(res);
				oos.flush();
				oos.close();
				ois.close();
				
			}
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

Client.java

package ch09.clinet;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

import ch09.model.Request;
import ch09.model.Response;
import ch09.model.User;

/**
 * 客户端
 * @author Administrator
 *
 */
public class Client {
	public static void main(String[] args) {
		try {
			Socket sc = new Socket("localhost", 9999);
			ObjectOutputStream oos = new ObjectOutputStream(sc.getOutputStream());
			//发送数据的封装
			Request req = new Request();
			req.setClassName("cn.edu360.day09.service.impl.UserServiceImpl");
			req.setMethodName("register");
			req.setParamTypes(new Class[]{User.class});
			req.setParamValues(new Object[]{new User("mingming", "1234", null, 0)});
			//发送数据
			oos.writeObject(req);
			oos.flush();
			
			ObjectInputStream ois = new ObjectInputStream(sc.getInputStream());
			//接收数据
			Object readObject = ois.readObject();
			Response res = (Response)readObject;
			System.out.println(res);
			sc.shutdownInput();
			sc.shutdownOutput();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

UserDaoImpl.java

package ch09.dao.impl;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import ch09.dao.UserDao;
import ch09.model.User;
import ch09.util.Const;
import ch09.util.FileUtiles;

public class UserDaoImpl implements UserDao{

	@Override
	public boolean save(User user) {
		File file = new File(Const.FILE_PATH);
		Map map = null;
		if(file.exists()){//当文件存在的时候,不是第一个保存的用户
			map = FileUtiles.getUserMapByFile();
			map.put(user.getUserName(), user);
		}else{//之前没有文件
			map = new HashMap<>();
			map.put(user.getUserName(), user);
		}
		//把所有的用户保存回去
		FileUtiles.saveMapToFile(map);
		return true;
	}

	@Override
	public User getUserByName(String userName) {
		File file = new File(Const.FILE_PATH);
		if(file.exists()){
			Map userMapByFile = FileUtiles.getUserMapByFile();
			User user = userMapByFile.get(userName);
			return user;
		}
		return null;
	}

}

UserDao.java

package ch09.dao;

import  ch09.model.User;

public interface UserDao {
	/**
	 * 保存user对象
	 * @param user
	 * @return
	 */
	boolean save(User user);
	
	/**
	 * 通过用户名获取用户对象
	 * @param userName
	 * @return
	 */
	User getUserByName(String userName);

}

TestFileUtile.java

package ch09.test;
/*
 * 
 * 测试类
 * 
 * 
 */
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import ch09.dao.UserDao;
import ch09.dao.impl.UserDaoImpl;
import ch09.model.User;
import ch09.model.UserResult;
import ch09.server.UserService;
/*import ch09.server.UimplserService;
*/import ch09.server.UserServiceImpl;
import ch09.util.FileUtiles;

public class TestFileUtile {
	
	@Test
	public void testFileUtile(){
		Map map = new HashMap<>();
		map.put("mingming", new User("mingming","123","明明",18));
		
		FileUtiles.saveMapToFile(map);
		Map userMapByFile = FileUtiles.getUserMapByFile();
		System.out.println(userMapByFile);
	}
	
	@Test
	public void testUserDao(){
		UserDao dao = new UserDaoImpl();
		//dao.save(new User("lainglaing", "123", "亮亮", 19));
		
		User userByName = dao.getUserByName("mingming");
		System.out.println(userByName);
	}
	
	@Test
	public void testUserService(){
		UserService service =new UserServiceImpl();
		UserResult result1 = service.login(new User("mingmin", "1234", null, 0));
		System.out.println(result1);
		
		
		UserResult result2 = service.register(new User("honghong", "123", "红红", 18));
		System.out.println(result2);
	}

}


你可能感兴趣的:(java)