您的位置:首页 > 理论基础 > 计算机网络

架构师日记——手写利用HTTP协议远程模块调用

2017-08-24 09:41 465 查看
远程模块调用比较流行的协议有RPC协议、RMI协议和HTTP协议

本篇博客教大家如何使用HTTP协议试远程模块的调用

1.定架构

总体架构如下



接下来我一个一个讲解他们的作用

2.ModuleModel

这个类的作用是记录不同uuid对应的module的信息,包括远端ip和url等,代码如下

/**
* 调用远端方法的协议类
*/
public class InteractiveModel {
/**
* 操作类型
*/
private String opeType;
/**
* 操作参数
*/
private Map<String,Object>map=new HashMap<String ,Object>();

public InteractiveModel(String opeType, Map<String, Object> map) {
this.opeType = opeType;
this.map = map;
}

public InteractiveModel() {
}

public String getOpeType() {
return opeType;
}

public void setOpeType(String opeType) {
this.opeType = opeType;
}

public Map<String, Object> getMap() {
return map;
}

public void setMap(Map<String, Object> map) {
this.map = map;
}
}


3.InteractiveModel

这个类可以说是调用方法的协议类,它包含操作类型和操作参数,代码如下

/**
* 调用远端方法的协议类
*/
public class InteractiveModel {
/**
* 操作类型
*/
private String opeType;
/**
* 操作参数
*/
private Map<String,Object>map=new HashMap<String ,Object>();

public InteractiveModel(String opeType, Map<String, Object> map) {
this.opeType = opeType;
this.map = map;
}

public InteractiveModel() {
}

public String getOpeType() {
return opeType;
}

public void setOpeType(String opeType) {
this.opeType = opeType;
}

public Map<String, Object> getMap() {
return map;
}

public void setMap(Map<String, Object> map) {
this.map = map;
}
}


4.InteractiveCallHelper

InteractiveCallHelper是调用远端方法的发起者,这个类可以独立于这个项目,为了方便我就我不把它单独提取出来了,既可以返回string也可以返还一个指定类型的对象。这个类的作用主要有以下几个

1.根据不同的uuid去获取到远端方法的url

2.实现参数中非法字符的转换

3.组合url和参数

代码如下

/**
* 调用远端方法的发起者
*/
public class InteractiveCallHelper {
/**
*
* @param moduleId 模块Id
* @param opeType 需要调用的具体的业务操作类型
* @param mapParams 调用所需要传递的参数
* @return 服务端返回的Json数据
*/
public String call(String moduleId, String opeType, Map<String,Object>mapParams){
//1.根据moduleId去获取到该模块部署的信息,理论上要根据moduleId去设置,这里写死
ModuleModel moduleModel=new ModuleModel();
moduleModel.setDeployIP("localhost");
moduleModel.setDeployPort("8080");
moduleModel.setIntereractiveUrl("/goods/call");

//2.准备要传递的数据,把Map转换为JSON
String paramStr= JSON.toJSONString(mapParams);
//因为#在url里有特殊含义,所以将#替换为*
paramStr=paramStr.replace("#","*");

//3.拼接一个远程调用的URL
String urlStr="http://"+ moduleModel.getDeployIP()+":"+moduleModel.getDeployPort()+moduleModel.getIntereractiveUrl()
+"?jsonParam={opeType:"+opeType+",map:"+paramStr+"}";

//4.使用URL进行远程调用,流式操作
BufferedReader in =null;
String retJson="";
try {
URL url=new URL(urlStr);
URLConnection urlConnection=url.openConnection();
// 定义 BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(
urlConnection.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
retJson += line;
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return retJson;
}

/**
*
* @param moduleId 模块Id
* @param opeType 需要调用的具体的业务操作类型
* @param mapParams 调用所需要传递的参数
* @param cls 需要转的类型
* @return  服务器返回的对象
*/
public <T>T call(String moduleId, String opeType, Map<String,Object>mapParams,Class<T> cls){
String json=call(moduleId,opeType,mapParams);
return JSON.parseObject(json,cls);
}

/**
* 测试方法
* @param args
*/
public static void main(String[]args){
InteractiveCallHelper interactiveCallHelper=new InteractiveCallHelper();
Map<String,Object>map=new HashMap<String,Object>();
String str=interactiveCallHelper.call("goods","1",map);
System.out.println(str);
}
}


5.InteractiveBaseController

这个类是远端被调用方法的基类,这个类是个抽象类,任何远端可被调用的controller都要继承它,继承call方法和实现它的doCall方法,代码如下

/**
* 远端被调用方法的基类
*/
public abstract class InteractiveBaseController {
/**
* 解析参数
* @param jsonParam
* @return
*/
@RequestMapping("/call")
@ResponseBody
public Object call(String jsonParam){
if (jsonParam!=null&&jsonParam.contains("*")){
//将*变回#
jsonParam=jsonParam.replace("*","#");
}
InteractiveModel interactiveModel= JSON.parseObject(jsonParam,InteractiveModel.class);
Object ret=doCall(interactiveModel.getOpeType(),interactiveModel.getMap());
return ret;
}
protected  abstract Object doCall(String opetype, Map<String,Object>map);
}


6.GoodsModel

这个类是JavaBean,和数据库对应的实体类,可自由替换,代码如下

/**
* 要操作的实体类
*/
public class GoodsModel {
private String uuid;
private String name;

public GoodsModel(String uuid, String name) {
this.uuid = uuid;
this.name = name;
}

public GoodsModel() {
}

public String getUuid() {
return uuid;
}

public void setUuid(String uuid) {
this.uuid = uuid;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return "GoodsModel{" +
"uuid='" + uuid + '\'' +
", name='" + name + '\'' +
'}';
}
}


7.GoodsController

远程方法示例,根据不同opetype执行不同的操作,如opetype为1时往数据库插入一个实体,代码如下

@RestController
@RequestMapping(value = "goods")
public class GoodsController extends InteractiveBaseController{

@Override
protected Object doCall(String opetype, Map<String, Object> map) {
//执行不同的操作
if ("1".equals(opetype)){

}else if ("2".equals(opetype)){

}
GoodsModel goodsModel=new GoodsModel();
goodsModel.setName("abc");
goodsModel.setUuid("132132");
System.out.println("call");
return goodsModel;
}
}


一个利用HTTP远程调用模块的Demo就写好了,但HTTP协议效率较低,所以在日常开发中,我们常常使用RPC协议实现远程调用模块,比如使用著名的Dubbo框架

完整代码已上传到github:https://github.com/jkgeekJack/UseRemoteInvoker

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐