apache hessian原理学习和自己实现rpc远程调用实例代码
因为最近有点时间,所以就想读一些技术的源码,最近选择hessian。废话不多说,进入正题:
hessian客户端时序图:
因为hessian源码相对于spring算很简单了。所以不浪费大家宝贵的时间来分析源码。想说说怎么实现远程调用(rpc)。
远程调用,顾名思义就是通过远程调用别的机器(JVM or ...)中的方法。要想实现远程调用,思路是怎样呢?
常用的模式代理,工厂。为啥怎么说呢?
远程调用通过网络,肯定需要工厂产出不同的类,不然一个类写,会死人的。
代理模式,因为调用前你是不知道实际的调用,肯定是通过代理调用到远程方法。
下面给大家说说远程调用的原理(PS:不懂代理的同学,先上百度搜索:java代理)。
实现自定义的远程调用,就是序列化成字节流后,发送到服务端,服务端根据调用的api、方法、参数去具体调用一个方法,调用方法后把结果输入到输出流里面,最后结果展示在代理的return中。
ok,开始贴代码:
客户端(HttpRpcClient):
String url = "http://localhost:8080/hessian-study-server/helloworld1";
HttpProxyFactory factory = new HttpProxyFactory();
Class<?> clazz = Class.forName("com.jzx.hessian.server.SayHelloService");
SayHelloService sayHelloService = (SayHelloService) factory.create(clazz, url);
System.out.println(sayHelloService.sayHello("小明", "男"));
UserVo vo = sayHelloService.sayHello1("小明", "男");
System.out.println("姓名:" + vo.getName() + " 性别:" + vo.getSex());
从代码中分析,首先创建了一个工厂类HttpProxyFactory,其次创建了一个类的描述。
HttpProxyFactory代码(主要目的是得到一个代理):
if (api == null) {
throw new NullPointerException("api must not be null for HttpProxyFactory.create()");
}
InvocationHandler handler = null;
handler = new HttpProxy(url, this, api);
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[] { api }, handler);
HttpProxy代理干了啥 (得到调用接口类、方法名、参数值):
HttpTransportation transportation = new HttpTransportation(); transportation.setClazz(api); transportation.setMethod(method.getName()); transportation.setParams(args); byte[] bytes = ObjectUtils.objectToByte(transportation); Object result = sendPost(url, bytes); return result;
序列化对象发送POST请求:
PrintWriter out = null;
BufferedReader in = null;
Object result = null;
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
OutputStream outputStream = conn.getOutputStream();
outputStream.write(param);
outputStream.close();
// 定义BufferedReader输入流来读取URL的响应
// in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
byte[] bytes = toByteArray(conn.getInputStream());
Object object = ObjectUtils.byteToObject(bytes);
if (object instanceof String) {
byte[] dest = new byte[bytes.length - 7];
System.arraycopy(bytes, 7, dest, 0, dest.length);
result = new String(dest, "UTF-8");
// result = new String(bytes, "UTF-8");
}
if (object instanceof UserVo) {
result = object;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!" + e);
e.printStackTrace();
}
// 使用finally块来关闭输出流、输入流
finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
以上是客户端的分割线------------------------服务端:
配置一个sevlet,初始化配置文件:
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
if (getInitParameter("home-api") != null) {
String className = getInitParameter("home-api");
try {
_homeAPI = Class.forName(className);
} catch (Exception e) {
}
}
if (getInitParameter("service-class") != null) {
String className = getInitParameter("service-class");
Class<?> clazz;
try {
clazz = Class.forName(className);
_homeImpl = clazz.newInstance();
} catch (Exception e) {
}
}
httpRpcSkeleton = new HttpRpcSkeleton(_homeAPI, _homeImpl);
}
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if (!req.getMethod().equals("POST")) {
res.setStatus(500); // , "Hessian Requires POST");
PrintWriter out = res.getWriter();
res.setContentType("text/html");
out.println("<h1>httrpc Requires POST</h1>");
return;
}
OutputStream out = res.getOutputStream();
try {
httpRpcSkeleton.invoke(req, out);
} catch (Exception e) {
e.printStackTrace();
} finally {
out.flush();
out.close();
}
}
看到请求最终被HttpRpcSkeleton的invoke调用,相关代码:
public void invoke(HttpServletRequest request, OutputStream out) throws Exception {
int len = request.getContentLength();
ServletInputStream input = request.getInputStream();
byte[] buffer = new byte[len];
input.read(buffer, 0, len);
HttpTransportation transportation = (HttpTransportation) ObjectUtils.byteToObject(buffer);
Method method = methodMap.get(transportation.getMethod());
Object result = method.invoke(_homeImpl, transportation.getParams());
out.write(ObjectUtils.objectToByte(result));
// out.write(result.getBytes());
}
以上就是实现远程,调用的原理。
另外对项目的说明,有兴趣的童鞋,可以试下不用java本身的序列化,试试protobuf。
另外有一个疑问困扰了一个晚上,当返回为字符串的时候,ObjectInputStream会多7个字节,不解,本人的java io很low,求解。
源码为maven结构:
运行时截图:
猜你喜欢
- /
- /hessian-study
- /hessian-study/modules
- /hessian-study/modules/hessian-study-server
- /hessian-study/modules/hessian-study-server/pom.xml
- /hessian-study/modules/hessian-study-server/src
- /hessian-study/modules/hessian-study-server/src/lib
- /hessian-study/modules/hessian-study-server/src/lib/hessian-4.0.37-src.jar
- /hessian-study/modules/hessian-study-server/src/lib/hessian-4.0.37.jar
- /hessian-study/modules/hessian-study-server/src/main
- /hessian-study/modules/hessian-study-server/src/main/java
- /hessian-study/modules/hessian-study-server/src/main/java/com
- /hessian-study/modules/hessian-study-server/src/main/java/com/jzx
- /hessian-study/modules/hessian-study-server/src/main/java/com/jzx/hessian
- /hessian-study/modules/hessian-study-server/src/main/java/com/jzx/hessian/client
- /hessian-study/modules/hessian-study-server/src/main/java/com/jzx/hessian/server
- /hessian-study/modules/hessian-study-server/src/main/java/com/jzx/hessian/vo
- /hessian-study/modules/hessian-study-server/src/main/java/com/jzx/httprpc
- /hessian-study/modules/hessian-study-server/src/main/java/com/jzx/hessian
- /hessian-study/modules/hessian-study-server/src/main/java/com/jzx
- /hessian-study/modules/hessian-study-server/src/main/java/com
- /hessian-study/modules/hessian-study-server/src/main/java
- /hessian-study/modules/hessian-study-server/src/lib
- /hessian-study/modules/hessian-study-server
- /hessian-study/modules
- /hessian-study
相关代码
最近下载
最近浏览




