- 自己实现简单rpc:
实现原理:客户端和服务端建立socket链接,客户端使用jdk代理,将要调用的方法的类名,方法名,方法参数类型,
方法参数通过socket输出流发送到server端,server端获取使用输入流读取这些内容,调用相关的实现类的方法,再将结果写入socket,客户端就获得了远程调用方法结果。
- client
/**
* Created by wanshenghua on 2018/3/30.
*/
public class ClientStub {
private static Socket
socket
;
public static <
T>
T
buildProxy(Class<
T> clazz
,String ip
,Integer port)
throws Throwable{
socket =
new Socket(ip
,port)
;
T t = (
T) Proxy.
newProxyInstance(clazz.getClassLoader()
, new Class[]{clazz}
,
proxyPerson())
;
//System.out.println(t);
return t
;
}
public static InvocationHandler
proxyPerson(){
return new InvocationHandler(){
@Override
public Object
invoke(Object proxy
, Method method
, Object[] args)
throws Throwable {
OutputStream outputStream =
socket.getOutputStream()
;
ObjectOutputStream oos =
new ObjectOutputStream(outputStream)
;
oos.writeObject(method.getDeclaringClass().getSimpleName())
;
oos.writeObject(method.getName())
;
oos.writeObject(method.getParameterTypes())
;
oos.writeObject(args)
;
oos.flush()
;
InputStream inputStream =
socket.getInputStream()
;
ObjectInputStream ois =
new ObjectInputStream(inputStream)
;
return ois.readObject()
;
}
}
;
}
}
- server
/**
* Created by wanshenghua on 2018/3/30.
*/
public class ServerStub {
private static int
port =
8888
;
private static ServerSocket
serverSocket
;
private static Map<String
,Object>
servicePool =
new HashMap<String
, Object>()
;
static {
servicePool.put(
"PersonService"
,new PersonServiceImpl())
;
}
public static void
main(String[] args)
throws Exception{
serverSocket =
new ServerSocket(
port)
;
while(
true){
publish()
;
}
}
public static void
publish()
throws Exception{
Socket accept =
serverSocket.accept()
;
InputStream inputStream = accept.getInputStream()
;
ObjectInputStream ois =
new ObjectInputStream(inputStream)
;
String className = (String) ois.readObject()
;
String methodName = (String) ois.readObject()
;
Class[] argsClass = (Class[]) ois.readObject()
;
Object[] args = (Object[]) ois.readObject()
;
Object tarObject =
servicePool.get(className)
;
Method method = tarObject.getClass().getMethod(methodName
, argsClass)
;
Object result = method.invoke(tarObject
, args)
;
OutputStream outputStream = accept.getOutputStream()
;
ObjectOutputStream oos =
new ObjectOutputStream(outputStream)
;
oos.writeObject(result)
;
oos.flush()
;
}
static class PersonServiceImpl
implements PersonService{
@Override
public Person
findById(
int personId) {
if(personId ==
1){
return new Person(personId
,
"wsh"
,
"man")
;
}
else{
return new Person(personId
,
"sumang"
,
"woman")
;
}
}
}
}
- Thrift
thrift启动服务端
public
class
Service {
public
static
void
main(String[] args)
throws
TTransportException {
TServerTransport serverTransport =
new
TServerSocket(
7777
);
// TProcessor实现类为由编译器生成的UserService.Processor,并将服务接口的实现类实例设置到对应的域上
TProcessor processor =
new
UserService.Processor<UserService.Iface>(
new
UserServiceImpl());
TServer.Args tArgs =
new
TServer.Args(serverTransport);
tArgs.processor(processor);
TServer server =
new
TSimpleServer(tArgs);
server.serve();
}
}
简单分析:
1.tserverTransport是服务传输对象,主要包装了socket编程中的serverTransport对象,用于获取来自客户端的socket连接,它有以下几个实现类:
其中TServerSocket支持同步io,TNonblockingServerSocket支持异步io.
2.
TProcessor为实现类的顶级接口,具体的实现,比如这里是UserServiceImpl需要我们自己去实现Iface接口中的方法。
3.args主要为thrift端的一些参数,它的继承关系如下:
其中AbstractServerArgs为Tserver的内部类,主要有以下几个属性:
当执行
TServer.Args tArgs =
new
TServer.Args(serverTransport);代码时,会调用该类的一个构造方法,将serverTransport再传递
给该类的serverTransport属性。现在我们看到这七个属性中六个属性都有值了,只有processorFactory,因此执行第四部代码
4.tArgs.processor(processor);会args对象中的processFactory赋值。
5.TServer server = new TSimpleServer(tArgs);将args中的参数全部赋给服务器对象。
6.server.serve();执行服务器对象的服务方法。
下面看看server.serce具体做了哪些事(这里以我们代码中的TSimpleServer为例):
try {
//设置一下内部的serverSocket属性的超时时间,serverSocket属性可以直接传入,也可以通过ip和port让TServerSocket自己内部构建
this.serverTransport_.listen()
;
}
catch (TTransportException var8) {
LOGGER.error(
"Error occurred during listening."
, var8)
;
return;
}
this.setServing(
true)
;
while(!
this.stopped_) {
TTransport client =
null;
TProcessor processor =
null;
TTransport inputTransport =
null;
TTransport outputTransport =
null;
TProtocol inputProtocol =
null;
TProtocol outputProtocol =
null;
try {
//通过上面说到的serverSocket属性获取来自客户端的socket连接,将socket的输入输出流包装成缓存输入输出流,将这些都作为TSocket的属性再返回
//TSocket是
TTtansprot一个子类,
client =
this.serverTransport_.accept()
;
if (client !=
null) {
processor =
this.processorFactory_.getProcessor(client)
;
//负责socket流的数据读取
inputTransport =
this.inputTransportFactory_.getTransport(client)
;
//负责socket流的数据写出
outputTransport =
this.outputTransportFactory_.getTransport(client)
;
//通过工厂得到协议层对象,上面我们看到该工厂对象默认为Factory对象,该对象返回一个使用二进制协议的对象,具体的传输则交给参数TTtansprot
inputProtocol =
this.inputProtocolFactory_.getProtocol(inputTransport)
;
outputProtocol =
this.outputProtocolFactory_.getProtocol(outputTransport)
;
while(
true) {
//根据inputProtocol,outputProtocol我们可以得到客户端调用的类名,方法名,参数类型,参数等信息,在处理器中进行查找调用,在写出
if (processor.process(inputProtocol
, outputProtocol)) {
continue;
}
}
}
}
在这里我们构建服务对象时的的很多参数都是默认的,比如
TTransportFactory inputTransportFactory =
new
TTransportFactory()
;
TTransportFactory outputTransportFactory =
new
TTransportFactory()
;
TProtocolFactory inputProtocolFactory =
new
Factory()
;
TProtocolFactory outputProtocolFactory =
new
Factory()
;
其实这些属性都可以由我们根据需求自由选择搭配,具体区别,可以参考(https://www.cnblogs.com/maociyuan/p/5718341.html)