RPC, remote Procedure call, which is generally speaking, calls a service on a remote computer as if it were a local service.
RPC can be based on HTTP or TCP protocol, Web Service is RPC based on HTTP protocol, it has good cross-platform, but its performance is inferior to RPC based on TCP protocol. Two aspects will directly affect the performance of RPC, one is the transmission mode, the second is serialization.
As we all know, TCP is the Transport layer protocol, HTTP is the application layer protocol, and the transport layer is lower than the application layer, in the data transmission, the lower the faster, so, in general, TCP must be faster than HTTP. In the case of serialization, Java provides the default serialization method, but in high concurrency, this approach will bring some performance bottlenecks, so there are a series of excellent serialization framework, such as: Protobuf, Kryo, Hessian, Jackson, etc., they can replace Java default serialization, which provides more efficient performance.
The following is a simple implementation based on Netty RPC calls.
First, define the entity classes for message passing
Span style= "FONT-SIZE:14PX;" >public class ClassInfo implements Serializable {private static final long Serialversionuid =-8970942815543515
064L; private string classname;//class name private string methodname;//function name private class<?>[] types;//parameter type P
Rivate object[] objects;//argument list 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;
Class<?>[] GetTypes () {return types;
} public void Settypes (class<?>[] types) {this.types = types;
Object[] GetObjects () {return objects;
} public void SetObjects (object[] objects) {this.objects = objects; }
}
Two, create the service side of the Netty operation, and the concrete Operation
1. Service Side
public class Rpcserver {private int port;
public rpcserver (int port) {this.port = port;
public void Start () {Eventloopgroup bossgroup = new Nioeventloopgroup ();
Eventloopgroup Workergroup = new Nioeventloopgroup (); try {serverbootstrap serverbootstrap = new Serverbootstrap (). Group (Bossgroup, Workergroup). Channel (Nioserve Rsocketchannel.class). LocalAddress (Port). Childhandler (New channelinitializer<socketchannel> () {@Override protected void Initchannel (Socketchannel ch) throws Exce
ption {Channelpipeline pipeline = Ch.pipeline ();
Pipeline.addlast (New Lengthfieldbasedframedecoder (Integer.max_value, 0, 4, 0, 4));
Pipeline.addlast (New Lengthfieldprepender (4)); Pipeline.addlast ("encoder", New ObjeCtencoder ());
Pipeline.addlast ("Decoder", New Objectdecoder (Integer.max_value, classresolvers.cachedisabled (null)));
Pipeline.addlast (New Invokerhandler ()); }). Option (Channeloption.so_backlog, 128). Childoption (Channeloption.so_
KEEPALIVE, True);
Channelfuture future = Serverbootstrap.bind (port). sync ();
System.out.println ("Server start listen at" + port);
Future.channel (). Closefuture (). sync ();
catch (Exception e) {bossgroup.shutdowngracefully ();
Workergroup.shutdowngracefully ();
} public static void Main (string[] args) throws Exception {int port;
if (Args.length > 0) {port = Integer.parseint (Args[0]);
else {port = 8080;
} New Rpcserver (Port). Start (); }
}
Service-side operations, by the service side we see the specific data transmission operation is serialized, the specific operation or relatively simple, is to obtain the information sent over, so you can get the class name through reflection, according to the function name and parameter value, perform specific operations, the results sent to the client
public class Invokerhandler extends Channelinboundhandleradapter {public static concurrenthashmap<string, Object
> classmap = new concurrenthashmap<string,object> (); @Override public void Channelread (Channelhandlercontext ctx, Object msg) throws Exception {ClassInfo
ClassInfo = (ClassInfo) msg;
Object claszz = null; if (!classmap.containskey (Classinfo.getclassname ())) {try {claszz = Class.forName (classinf
O.getclassname ()). Newinstance ();
Classmap.put (Classinfo.getclassname (), CLASZZ); catch (Instantiationexception | illegalaccessexception |
ClassNotFoundException e) {e.printstacktrace ();
}}else {claszz = Classmap.get (Classinfo.getclassname ());
Method method = Claszz.getclass (). GetMethod (Classinfo.getmethodname (), classinfo.gettypes ()); Object result = Method.invoke (clAszz, Classinfo.getobjects ());
Ctx.write (result);
Ctx.flush ();
Ctx.close ();
@Override public void Exceptioncaught (Channelhandlercontext ctx, Throwable cause) throws Exception {
Cause.printstacktrace ();
Ctx.close ();
}
}
Third, the client, through the proxy mechanism to trigger the remote call
(1) client, when the implementation of specific functions will invoke remote operations, the specific operation of the class, function and parameter information sent to the service side
public class RpcProxy {@SuppressWarnings (' unchecked ') public static <T> T Create (Object target) { Return (T) proxy.newproxyinstance (Target.getclass (). getClassLoader (), Target.getclass (). Getinterfaces (), New Invocationhandler () {@Override public object Invoke (Object Proxy, Method method, object[] Arg
s) throws Throwable {ClassInfo ClassInfo = new ClassInfo ();
Classinfo.setclassname (Target.getclass (). GetName ());
Classinfo.setmethodname (Method.getname ());
Classinfo.setobjects (args);
Classinfo.settypes (Method.getparametertypes ());
Resulthandler Resulthandler = new Resulthandler ();
Eventloopgroup Group = new Nioeventloopgroup ();
try {Bootstrap b = new Bootstrap (); B.group (Group). Channel (Niosocketchannel.class). Option (Channeloption.tcp_nodelay, True). Handler ( New Channelinitializer<socketchannel> () {@Override public void Initchannel (Socketchannel ch) throws Exception {Channelpipeline pipeline = Ch.pipe
Line ();
Pipeline.addlast ("Framedecoder", New Lengthfieldbasedframedecoder (Integer.max_value, 0, 4, 0, 4));
Pipeline.addlast ("Frameencoder", New Lengthfieldprepender (4));
Pipeline.addlast ("encoder", New Objectencoder ());
Pipeline.addlast ("Decoder", New Objectdecoder (Integer.max_value, classresolvers.cachedisabled (null)));
Pipeline.addlast ("handler", Resulthandler);
}
}); Channelfuture FutuRe = B.connect ("localhost", 8080). sync ();
Future.channel (). Writeandflush (ClassInfo). sync ();
Future.channel (). Closefuture (). sync ();
finally {group.shutdowngracefully ();
return Resulthandler.getresponse ();
}
}); }
}
Gets the result value returned by the remote call
public class Resulthandler extends Channelinboundhandleradapter {
private Object response;
Public Object GetResponse () {return
response;
}
@Override public
void Channelread (Channelhandlercontext ctx, Object msg) throws Exception {
response=msg;
SYSTEM.OUT.PRINTLN ("Client receives the message returned by the server:" + msg);
}
@Override public
void Exceptioncaught (Channelhandlercontext ctx, Throwable cause) throws Exception {
SYSTEM.OUT.PRINTLN ("Client exception is General");
}
Iv. interface, implementation class and main operation
Public interface Hellorpc {
string hello (string name);
}
public class Hellorpcimpl implements HELLORPC {
@Override public
string Hello (string name) {return
" Hello "+name;
}
}"