RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议。它允许像调用本地服务一样调用远程服务。它可以有不同的实现方式。如RMI(远程方法调用)、Hessian、Http invoker等。另外,RPC是与语言无关的。
项目地址:http://download.csdn.net/detail/u013725455/9784408
InvokeModel类,封装了参数类型、参数值、服务接口
/*
* 文件名:InvokeModel.java
* 版权:Copyright 2007-2017 517na Tech. Co. Ltd. All Rights Reserved.
* 描述: InvokeModel.java
* 修改人:peiyu
* 修改时间:2017年3月17日
* 修改内容:新增
*/
package com.rpc.model;
import java.io.Serializable;
/**
*
* @author peiyu
*/
@SuppressWarnings("rawtypes")
public class InvokeModel implements Serializable{
/**
* 添加字段注释.
*/
private static final long serialVersionUID = 1L;
private String methodName;
private String serviceName;
private Object[] params;
private Class[] paramsType;
/**
* 设置methodName.
* @return 返回methodName
*/
public String getMethodName() {
return methodName;
}
/**
* 设置serviceName.
* @return 返回serviceName
*/
public String getServiceName() {
return serviceName;
}
/**
* 设置params.
* @return 返回params
*/
public Object[] getParams() {
return params;
}
/**
* 获取methodName.
* @param methodName 要设置的methodName
*/
public void setMethodName(String methodName) {
this.methodName = methodName;
}
/**
* 获取serviceName.
* @param serviceName 要设置的serviceName
*/
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
/**
* 获取params.
* @param params 要设置的params
*/
public void setParams(Object[] params) {
this.params = params;
}
/**
* 设置paramsType.
* @return 返回paramsType
*/
public Class[] getParamsType() {
return paramsType;
}
/**
* 获取paramsType.
* @param paramsType 要设置的paramsType
*/
public void setParamsType(Class[] paramsType) {
this.paramsType = paramsType;
}
}
RPCClient类,客户端远程调用服务端
/*
* 文件名:PRCClient.java
* 版权:Copyright 2007-2017 517na Tech. Co. Ltd. All Rights Reserved.
* 描述: PRCClient.java
* 修改人:peiyu
* 修改时间:2017年3月17日
* 修改内容:新增
*/
package com.rpc.client;
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.InetSocketAddress;
import java.net.Socket;
import com.alibaba.fastjson.JSON;
import com.rpc.model.InvokeModel;
import com.rpc.util.CloseUtil;
/**
* @author peiyu
*/
public class RPCClient {
@SuppressWarnings("unchecked")
public static T getPRCProxy(Class clazz, final InetSocketAddress addr) {
return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class>[]{clazz}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket socket = null;
ObjectInputStream ois = null;
ObjectOutputStream oos = null;
try {
socket = new Socket();
socket.connect(addr);
oos = new ObjectOutputStream(socket.getOutputStream());
InvokeModel invokeModel = getInvokeModel(clazz, method, args);
oos.writeUTF(JSON.toJSONString(invokeModel));
oos.flush();
ois = new ObjectInputStream(socket.getInputStream());
return ois.readUTF();
} finally {
CloseUtil.close(socket);
CloseUtil.close(oos);
CloseUtil.close(ois);
}
}
});
}
private static InvokeModel getInvokeModel(Class clazz, Method method, Object[] args) {
InvokeModel invokeModel = new InvokeModel();
invokeModel.setMethodName(method.getName());
invokeModel.setParams(args);
invokeModel.setServiceName(clazz.getName());
invokeModel.setParamsType(method.getParameterTypes());
return invokeModel;
}
}
RPCServer 接口,RPC提供的接口
/*
* 文件名:PRCServer.java
* 版权:Copyright 2007-2017 517na Tech. Co. Ltd. All Rights Reserved.
* 描述: PRCServer.java
* 修改人:peiyu
* 修改时间:2017年3月17日
* 修改内容:新增
*/
package com.rpc.server;
/**
*
* @author peiyu
*/
public interface RPCServer {
public void stop();
public void start() throws Throwable;
public void register(Class> service, Class> serviceImpl);
public int getPort();
public boolean isRuning();
}
RPC接口实现类,监听客户端的远程请求
/*
* 文件名:PRCServerCenter.java
* 版权:Copyright 2007-2017 517na Tech. Co. Ltd. All Rights Reserved.
* 描述: PRCServerCenter.java
* 修改人:peiyu
* 修改时间:2017年3月17日
* 修改内容:新增
*/
package com.rpc.server;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.rpc.util.CloseUtil;
/**
* @author peiyu
*/
public class RPCServerCenter implements RPCServer {
private static Map> registerCenter = new HashMap<>();
private ExecutorService executor = Executors.newCachedThreadPool();
private boolean isRunnig = false;
private int port = 80;
public RPCServerCenter(int port) {
this.port = port;
}
@Override
public void stop() {
try {
executor.shutdown();
} finally {
isRunnig = false;
}
}
@Override
public void start() throws Throwable {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress(port));
System.out.println("server start at listen to " + port+"。。。。。。");
isRunnig = true;
while (true) {
executor.execute(new RPCServiceHandler(serverSocket.accept(), registerCenter));
}
} finally {
CloseUtil.close(serverSocket);
}
}
@Override
public void register(Class> service, Class> serviceImpl) {
registerCenter.put(service.getName(), serviceImpl);
}
@Override
public int getPort() {
return this.port;
}
@Override
public boolean isRuning() {
return this.isRunnig;
}
}
RPCServiceHandler 类,请求处理,找到调用接口,进行业务处理并返回结果
/*
* 文件名:PRCServiceHandler.java
* 版权:Copyright 2007-2017 517na Tech. Co. Ltd. All Rights Reserved.
* 描述: PRCServiceHandler.java
* 修改人:peiyu
* 修改时间:2017年3月17日
* 修改内容:新增
*/
package com.rpc.server;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.Socket;
import java.util.Map;
import com.alibaba.fastjson.JSON;
import com.rpc.model.InvokeModel;
import com.rpc.util.CloseUtil;
/**
* @author peiyu
*/
public class RPCServiceHandler implements Runnable {
private Socket client;
private Map> registerCenter;
public RPCServiceHandler(Socket client, Map> registerCenter) {
this.client = client;
this.registerCenter = registerCenter;
}
public void run() {
ObjectInputStream input = null;
ObjectOutputStream output = null;
try {
//将客户端发送的码流反序列化成对象,反射调用服务实现者,获取执行结果
input = new ObjectInputStream(client.getInputStream());
String param =input.readUTF();
System.out.println("请求参数:" + param);
InvokeModel invokeModel = JSON.parseObject(param, InvokeModel.class);
Class> serviceClass = registerCenter.get(invokeModel.getServiceName());
if (serviceClass == null) {
throw new ClassNotFoundException(invokeModel.getServiceName() + " not found");
}
Method method = serviceClass.getMethod(invokeModel.getMethodName(), invokeModel.getParamsType());
Object result = method.invoke(serviceClass.newInstance(), invokeModel.getParams());
System.out.println("返回结果:" + JSON.toJSONString(result));
//将执行结果反序列化,通过socket发送给客户端
output = new ObjectOutputStream(client.getOutputStream());
output.writeUTF(JSON.toJSONString(result));
output.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
CloseUtil.close(output);
CloseUtil.close(input);
CloseUtil.close(client);
}
}
}
服务接口
/*
* 文件名:ISayHello.java
* 版权:Copyright 2007-2017 517na Tech. Co. Ltd. All Rights Reserved.
* 描述: ISayHello.java
* 修改人:peiyu
* 修改时间:2017年3月17日
* 修改内容:新增
*/
package com.rpc.service;
/**
* @author peiyu
*/
public interface ISayHello {
public String sayHello(String name);
}
接口的实现
/*
* 文件名:SayHelloImpl.java
* 版权:Copyright 2007-2017 517na Tech. Co. Ltd. All Rights Reserved.
* 描述: SayHelloImpl.java
* 修改人:peiyu
* 修改时间:2017年3月17日
* 修改内容:新增
*/
package com.rpc.service;
/**
* @author peiyu
*/
public class SayHelloImpl implements ISayHello {
@Override
public String sayHello(String name) {
System.out.println(name+" : hello world");
return name+" : hello world";
}
}
测试启动服务
/*
* 文件名:Test.java
* 版权:Copyright 2007-2017 517na Tech. Co. Ltd. All Rights Reserved.
* 描述: Test.java
* 修改人:peiyu
* 修改时间:2017年3月17日
* 修改内容:新增
*/
package com.rpc.test;
import com.rpc.server.RPCServer;
import com.rpc.server.RPCServerCenter;
import com.rpc.service.ISayHello;
import com.rpc.service.SayHelloImpl;
/**
* @author peiyu
*/
public class ServerTest {
public static void main(String[] args) throws Throwable {
RPCServer prcServer=new RPCServerCenter(8888);
prcServer.register(ISayHello.class, SayHelloImpl.class);
prcServer.start();
}
}
测试客户端请求
/*
* 文件名:Test.java
* 版权:Copyright 2007-2017 517na Tech. Co. Ltd. All Rights Reserved.
* 描述: Test.java
* 修改人:peiyu
* 修改时间:2017年3月17日
* 修改内容:新增
*/
package com.rpc.test;
import java.net.InetSocketAddress;
import com.rpc.client.RPCClient;
import com.rpc.service.ISayHello;
/**
* @author peiyu
*/
public class ClientTest {
public static void main(String[] args) {
InetSocketAddress addr = new InetSocketAddress("localhost", 8888);
ISayHello sayHello = RPCClient.getPRCProxy(ISayHello.class, addr);
System.out.println("prc返回:" + sayHello.sayHello("张三"));
}
}
结果:
【客户端】
prc返回:"张三 : hello world"
【服务端】
server start at listen to 8888
请求参数:{"methodName":"sayHello","params":["张三"],"paramsType":["java.lang.String"],"serviceName":"com.rpc.service.ISayHello"}
张三 : hello world
返回结果:"张三 : hello world"