最开始的时候,公司没有采用任何SOA架构。
(虽然用到了COM,但没有用到DCOM)
(用到了SOAP,但仅仅是做接口使用)
2011年,开始用EJB,但只在一个项目使用了EJB。
2012年,突然涌进了大量的接口,于是求救于ESB,成为了下面的样子。
ESB+SOAP
ESB+HL7
ESB+REST
2015年,开始向RPC框架求救。
ESB+Dubbo+(SOAP/REST/HLU)
Learn and share.
最开始的时候,公司没有采用任何SOA架构。
(虽然用到了COM,但没有用到DCOM)
(用到了SOAP,但仅仅是做接口使用)
2011年,开始用EJB,但只在一个项目使用了EJB。
2012年,突然涌进了大量的接口,于是求救于ESB,成为了下面的样子。
ESB+SOAP
ESB+HL7
ESB+REST
2015年,开始向RPC框架求救。
ESB+Dubbo+(SOAP/REST/HLU)
接第01部分,本节用来说明Java语言的代码实现。
使用Protoc.exe生成java代码之后,会生成两个java文件,Client与Server都需要包含这两个文件。
首先是Server端:
1、新建一个java项目,引用以下jar包
protobuf-java-3.0.0-beta-2.jar
grpc-all-0.13.1.jar
guava-18.0.jar
netty-all-4.1.0.CR1.jar
okhttp-2.5.0.jar
okio-1.6.0.jar
2、项目中添加生成的两个java文件。
3、新建一个类MyGRPCServer,实现JustATestGrpc.JustATest接口
package com.neohope.protobuf.grpc.test;
import io.grpc.stub.StreamObserver;
public class MyGRPCServer implements JustATestGrpc.JustATest{
@Override
public void add(JustATestOuterClass.AddRequest request, StreamObserver<JustATestOuterClass.AddResponse> responseObserver) {
JustATestOuterClass.AddResponse rsp = JustATestOuterClass.AddResponse.newBuilder().setC(request.getA() + request.getB()).build();
responseObserver.onNext(rsp);
responseObserver.onCompleted();
}
@Override
public void sayHelloTo(JustATestOuterClass.Person request, StreamObserver<JustATestOuterClass.HelloResponse> responseObserver) {
JustATestOuterClass.HelloResponse rsp = JustATestOuterClass.HelloResponse.newBuilder().setRsp("Hello "+ request.getName()).build();
responseObserver.onNext(rsp);
responseObserver.onCompleted();
}
}
4、修改TestServer.java
package com.neohope.protobuf.grpc.test;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.netty.NettyServerBuilder;
import java.io.IOException;
import java.util.Scanner;
public class TestServer {
public static void main(String[] args) throws IOException {
Server server = NettyServerBuilder.forPort(1900)
.addService(JustATestGrpc.bindService(new MyGRPCServer()))
.build()
.start();
Scanner scanner =new Scanner(System.in);
scanner.nextLine();
}
}
5、编译运行
然后是Client端:
1、新建一个java项目,引用以下jar包
protobuf-java-3.0.0-beta-2.jar
grpc-all-0.13.1.jar
guava-18.0.jar
netty-all-4.1.0.CR1.jar
okhttp-2.5.0.jar
okio-1.6.0.jar
2、项目中添加生成的两个java文件。
3、修改TestClient.java
package com.neohope.protobuf.grpc.test;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
public class TestClient {
public static void main(String[] args)
{
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 1900)
.usePlaintext(true)
.build();
JustATestGrpc.JustATestBlockingStub blockingStub = JustATestGrpc.newBlockingStub(channel);
JustATestOuterClass.AddRequest areq = JustATestOuterClass.AddRequest.newBuilder().setA(1).setB(2).build();
JustATestOuterClass.AddResponse arsp = blockingStub.add(areq);
System.out.println(arsp.getC());
JustATestOuterClass.Person preq = JustATestOuterClass.Person.newBuilder().setAge(30).setName("neohope").setSex(JustATestOuterClass.Person.SexType.MALE).build();
JustATestOuterClass.HelloResponse prsp = blockingStub.sayHelloTo(preq);
System.out.println(prsp.getRsp());
channel.shutdown();
}
}
4、编译运行
接第01部分,本节用来说明C#语言的代码实现。
使用Protoc.exe生成cs代码之后,会生成两个cs文件,Client与Server都需要包含这两个文件。
首先是Server端:
1、新建一个Console项目,引用Protoc程序集中以下几个dll文件,并添加生成的CS文件
Google.Protobuf.dll
Grpc.Core.dll
System.Interactive.Async.dll
2、新建一个类MyGRPCServer,实现JustATest.IJustATest接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Com.Neohope.Protobuf.Grpc.Test;
using Grpc.Core;
namespace TestProtoBufferCliet
{
class MyGRPCServer : JustATest.IJustATest
{
public Task<AddResponse> Add(AddRequest request, ServerCallContext context)
{
AddResponse rsp = new AddResponse();
rsp.C = request.A + request.B;
return Task.FromResult(rsp);
}
public Task<HelloResponse> SayHelloTo(Person request, ServerCallContext context)
{
HelloResponse rsp = new HelloResponse();
rsp.Rsp = "Hello " + request.Name;
return Task.FromResult(rsp);
}
}
}
3、修改Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Com.Neohope.Protobuf.Grpc.Test;
using Grpc.Core;
using TestProtoBufferCliet;
namespace TestProtoBuffer
{
class Program
{
static void Main(string[] args)
{
Server server = new Server
{
Services = { JustATest.BindService(new MyGRPCServer()) },
Ports = { new ServerPort("localhost", 1900, ServerCredentials.Insecure) }
};
server.Start();
}
}
}
4、编译运行
其中,非托管dll要如下放置
.
│ yourprogram.exe
│
└─nativelibs
├─windows_x64
│ grpc_csharp_ext.dll
│
└─windows_x86
grpc_csharp_ext.dll
然后是Client端:
1、新建一个Console项目,引用Protoc程序集中以下几个dll文件,并添加生成的CS文件
Google.Protobuf.dll
Grpc.Core.dll
System.Interactive.Async.dll
2、修改Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Com.Neohope.Protobuf.Grpc.Test;
using Grpc.Core;
namespace TestProtoBufferCliet
{
class Program
{
static void Main(string[] args)
{
Channel channel = new Channel("127.0.0.1:1900", ChannelCredentials.Insecure);
JustATest.JustATestClient client = JustATest.NewClient(channel);
Person p = new Person();
p.Name = "neohope";
p.Age = 30;
p.Sex = Person.Types.SexType.MALE;
HelloResponse prsp = client.SayHelloTo(p);
Console.WriteLine(prsp.Rsp);
AddRequest areq = new AddRequest();
areq.A = 1;
areq.B = 2;
AddResponse arsp = client.Add(areq);
Console.WriteLine(arsp.C);
channel.ShutdownAsync().Wait();
Console.ReadLine();
}
}
}
3、编译运行
其中,非托管dll要如下放置
.
│ yourprogram.exe
│
└─nativelibs
├─windows_x64
│ grpc_csharp_ext.dll
│
└─windows_x86
grpc_csharp_ext.dll
ProtocolBuffer大家多是使用其强大的序列化功能。但从3.0版本起,官方提供了GRPC作为其RPC功能的扩展。同样可以用于跨语言RPC通讯了哦。其通信架构如下图所示:

使用ProtocolBuffer+GRPC的时候,首先要先下载ProtocolBuffer、GRPC,各种语言的编译工具及语言支持包,本例主要用到C#和Java。
ProtoBuffer的编译工具:
protoc.exe
可以到github下载
Java的工具及支持包,都可以到mvnrepository下载到
protobuf-java-3.0.0-beta-2.jar
grpc-all-0.13.1.jar
guava-18.0.jar
netty-all-4.1.0.CR1.jar
okhttp-2.5.0.jar
okio-1.6.0.jar
protoc-gen-grpc-java.exe(protoc-gen-grpc-java-0.13.1-windows-x86_32.exe 或 protoc-gen-grpc-java-0.13.1-windows-x86_64.exe)
C#的工具及支持包,都可以到NuGet上下载到
Google.Protobuf.dll(测试时NuGet没有3.0版本,我从github下源码,把源码从CS6.0人肉降级到CS5.0,用VS2013把编译通过)
Grpc.Core.dll
grpc_csharp_ext.dll(32及64版本)
System.Interactive.Async.dll
grpc_csharp_plugin.exe
使用新版本ProtocolBuffer+GRPC的时候,先定义一个接口描述文件,比如我自己写了一个很简单的接口。
JustATest.proto
syntax = "proto3";
option java_package = "com.neohope.protobuf.grpc.test";
package com.neohope.protobuf.grpc.test;
service JustATest {
rpc Add (AddRequest) returns (AddResponse){}
rpc SayHelloTo (Person) returns (HelloResponse);
}
message Person {
enum SexType {
MALE = 0;
FEMALE = 1;
OTHER = 2;
UNKNOWN = 4;
}
string name = 1;
SexType sex = 2;
int32 age = 3;
}
message HelloResponse {
string rsp = 1;
}
message AddRequest {
int32 a = 1;
int32 b = 2;
}
message AddResponse {
int32 c = 1;
}
然后,工具分别编译为java及c#语言
#CS protoc.exe --plugin=protoc-gen-grpc=grpc_csharp_plugin.exe --grpc_out gen-cs -I. --csharp_out gen-cs JustATest.proto #Java protoc.exe --plugin=protoc-gen-grpc=protoc-gen-grpc-java.exe --grpc_out gen-java -I. --java_out gen-java JustATest.proto
接第01部分,本节用来说明Java语言的代码实现。
使用avro生成java代码之后,会生成两个java文件,无论是Client还是Server都要包含这两个文件。
首先是Server端:
1、新建一个java项目,引用以下jar包
avro-1.8.0.jar
avro-ipc-1.8.0.jar
jackson-core-asl-1.9.13.jar
jackson-mapper-asl-1.9.13.jar
netty-3.5.13.Final.jar
slf4j-api-1.7.7.jar
slf4j-simple-1.7.7.jar
2、项目中添加生成的两个java文件。
3、新建一个类MyAvroServer,实现JustATest接口
package com.neohope.avro.test;
import org.apache.avro.AvroRemoteException;
public class MyAvroServer implements JustATest{
@Override
public CharSequence SayHelloTo(Person person) throws AvroRemoteException {
return "Hello "+person.getName();
}
@Override
public int Add(int a, int b) throws AvroRemoteException {
return a+b;
}
}
4、修改TestServer.java
package com.neohope.avro.test;
import org.apache.avro.ipc.NettyServer;
import org.apache.avro.ipc.specific.SpecificResponder;
import java.net.InetSocketAddress;
import java.util.Scanner;
public class TestServer {
public static void main(String[] args) {
NettyServer server = new NettyServer(new SpecificResponder(
JustATest.class,
new MyAvroServer()),
new InetSocketAddress(1900));
server.start();
Scanner sc=new Scanner(System.in);
sc.nextLine();
server.close();
}
}
5、编译运行
然后是Client端:
1、新建一个java项目,引用以下jar包
avro-1.8.0.jar
avro-ipc-1.8.0.jar
jackson-core-asl-1.9.13.jar
jackson-mapper-asl-1.9.13.jar
netty-3.5.13.Final.jar
slf4j-api-1.7.7.jar
slf4j-simple-1.7.7.jar
2、项目中添加生成的两个java文件。
3、修改TestClient.java
package com.neohope.avro.test;
import org.apache.avro.AvroRemoteException;
import org.apache.avro.ipc.NettyTransceiver;
import org.apache.avro.ipc.specific.SpecificRequestor;
import org.apache.avro.util.Utf8;
import java.io.IOException;
import java.net.InetSocketAddress;
public class TestClient {
public static void main(String[] args) throws IOException {
NettyTransceiver client = new NettyTransceiver(new InetSocketAddress("localhost",1900));
JustATest proxy = (JustATest) SpecificRequestor.getClient(JustATest.class, client);
Person person = new Person();
person.setSex(new Utf8("male"));
person.setName(new Utf8("neohope"));
person.setAddress(new Utf8("shanghai"));
System.out.println(proxy.SayHelloTo(person));
System.out.println(proxy.Add(1,2));
client.close();
}
}
4、编译运行
接第01部分,本节用来说明C#语言的代码实现。
使用avro生成cs代码之后,会生成三个cs文件,Client与Server需要分别包含这三个文件。
首先是Server端:
1、新建一个Console项目,引用Avro程序集中以下几个dll文件
Avro.dll
Avro.ipc.dll
Castle.Core.dll
log4net.dll
Newtonsoft.Json.dll
2、项目中添加生成的以下几个cs文件
JustATest.cs
Person.cs
3、新建一个类MyAvroServer,实现JustATest接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using com.neohope.avro.test;
namespace TestAvro.com.neohope.avro.test
{
class MyAvroServer : JustATest
{
public override string SayHelloTo(Person person)
{
return "Hello " + person.name;
}
public override int Add(int a, int b)
{
return a + b;
}
}
}
4、修改Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using Avro.ipc;
using Avro.ipc.Specific;
using com.neohope.avro.test;
using TestAvro.com.neohope.avro.test;
namespace TestAvro
{
class Program
{
static void Main(string[] args)
{
SpecificResponder<JustATest> responder = new SpecificResponder<JustATest>(new MyAvroServer());
SocketServer server = new SocketServer("localhost", 1900, responder);
server.Start();
Console.ReadLine();
server.Stop();
}
}
}
5、编译运行
然后是Client端:
1、新建一个Console项目,引用Avro程序集中以下几个dll文件
Avro.dll
Avro.ipc.dll
Castle.Core.dll
log4net.dll
Newtonsoft.Json.dll
2、项目中添加生成的以下几个cs文件
JustATestCallback.cs
JustATest.cs
Person.cs
3、修改Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Avro.ipc;
using Avro.ipc.Specific;
using com.neohope.avro.test;
namespace TestAvroClient
{
class Program
{
static void Main(string[] args)
{
SocketTransceiver transceiver = new SocketTransceiver("localhost", 1900);
JustATestCallback proxy = SpecificRequestor.CreateClient<JustATestCallback>(transceiver);
Person person = new Person();
person.sex = "male";
person.name = "neohope";
person.address = "shanghai";
Console.WriteLine(proxy.SayHelloTo(person));
Console.WriteLine(proxy.Add(1, 2));
transceiver.Close();
}
}
}
4、编译运行
Avro也是典型CS架构,与ICE、CORBA、Thrift相同,但大家一般不太用其做RPC框架,而多是使用其强大的序列化功能。即使如此,我们也可以将Avro用于RPC通讯,也只需要告诉Avro服务在哪里,需要哪个服务,调用参数是什么,然后就坐等处理结果就好咯。
使用Avro的时候,首先要先下载Avro的开发包,每种序言需要单独下载,都自带编译工具及语言支持包,本例主要用到C#和Java。
Avro
使用新版本Avro的时候,一般显示用IDL语言,定义一个接口描述文件,比如我自己写了一个很简单的接口。
JustATest.avdl
@namespace("com.neohope.avro.test")
protocol JustATest{
record Person {
string name;
int age;
string sex;
string address;
}
string SayHelloTo(Person person);
int Add(int a,int b);
}
然后用Avro自带工具,将其翻译为protocol文件
JustATest.avpr
set AVRO_HOME=D:\Build\Avro\avro-java-1.8.0 java -jar %AVRO_HOME%\avro-tools-1.8.0.jar idl JustATest.avdl JustATest.avpr
翻译得到的JustATest.avpr文件如下:
{
"protocol" : "JustATest",
"namespace" : "com.neohope.avro.test",
"types" : [ {
"type" : "record",
"name" : "Person",
"fields" : [ {
"name" : "name",
"type" : "string"
}, {
"name" : "age",
"type" : "int"
}, {
"name" : "sex",
"type" : "string"
}, {
"name" : "address",
"type" : "string"
} ]
} ],
"messages" : {
"SayHelloTo" : {
"request" : [ {
"name" : "person",
"type" : "Person"
} ],
"response" : "string"
},
"Add" : {
"request" : [ {
"name" : "a",
"type" : "int"
}, {
"name" : "b",
"type" : "int"
} ],
"response" : "int"
}
}
}
然后,用工具分别编译为java及c#语言
#java set AVRO_HOME=D:\Build\Avro\avro-java-1.8.0 java -jar %AVRO_HOME%\avro-tools-1.8.0.jar compile protocol JustATest.avpr avpr #c# avrogen -p JustATest.avpr avpr-cs
接第01部分,本节用来说明Java语言的代码实现。
使用thrift生成java代码之后,会生成两个java文件,无论是Client还是Server都要包含这个文件。
首先是Server端:
1、新建一个java项目,引用libthrift.jar,项目中添加生成的两个java文件。
2、新建一个类MyThriftServer,实现JustATest.Iface接口
package com.neohope.thrift.test;
import org.apache.thrift.TException;
public class MyThriftServer implements JustATest.Iface {
@Override
public String SayHelloTo(Person person) throws TException {
return "Hello "+ person.getName();
}
@Override
public int Add(int a, int b) throws TException {
return a+b;
}
}
3、修改TestServer.java
package com.neohope.thrift.test;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TTransportException;
public class TestServer {
public static void main(String[] args) {
try {
TServerSocket serverTransport = new TServerSocket(1900);
JustATest.Processor process = new JustATest.Processor(new MyThriftServer());
TBinaryProtocol.Factory portFactory = new TBinaryProtocol.Factory(true, true);
TThreadPoolServer.Args thriftArgs = new TThreadPoolServer.Args(serverTransport);
thriftArgs.processor(process);
thriftArgs.protocolFactory(portFactory);
TServer server = new TThreadPoolServer(thriftArgs);
server.serve();
} catch (TTransportException e) {
e.printStackTrace();
}
}
}
4、编译运行
然后是Client端:
1、新建一个java项目,引用libthrift.jar,项目中添加生成的两个java文件。
2、修改TestClient.java
package com.neohope.thrift.test;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;
public class TestClient {
public static void main(String[] args) {
TTransport transport;
try {
transport = new TSocket("localhost", 1900);
TProtocol protocol = new TBinaryProtocol(transport);
JustATest.Client client = new JustATest.Client(protocol);
transport.open();
Person p = new Person();
p.setName("neohope");
System.out.println(client.SayHelloTo(p));
System.out.println(client.Add(1, 2));
transport.close();
} catch (TTransportException e) {
e.printStackTrace();
} catch (TException e) {
e.printStackTrace();
}
}
}
3、编译运行
接第01部分,本节用来说明C#语言的代码实现。
使用thrift生成cs代码之后,会生成两个cs文件,无论是Client还是Server都要包含这个文件。
首先是Server端:
1、新建一个Console项目,引用Thrift程序集中的Thrift.dll,项目中添加生成的两个cs文件。
2、新建一个类MyThriftServer,实现JustATest.Iface接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestThrift
{
class MyThriftServer : JustATest.Iface
{
public string SayHelloTo(Person person)
{
return "Hello " + person.Name;
}
public int Add(int a, int b)
{
return a + b;
}
}
}
3、修改Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Thrift.Protocol;
using Thrift.Server;
using Thrift.Transport;
namespace TestThrift
{
class Program
{
static void Main(string[] args)
{
TServerSocket serverTransport = new TServerSocket(1900, 0, false);
JustATest.Processor processor = new JustATest.Processor(new MyThriftServer());
TServer server = new TSimpleServer(processor, serverTransport);
server.Serve();
}
}
}
4、编译运行
然后是Client端:
1、新建一个Console项目,引用Thrift程序集中的Thrift.dll,项目中添加生成的两个cs文件。
2、修改Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Thrift.Protocol;
using Thrift.Transport;
namespace TestThriftClient
{
class Program
{
static void Main(string[] args)
{
TTransport transport = new TSocket("localhost", 1900);
TProtocol protocol = new TBinaryProtocol(transport);
JustATest.Client client = new JustATest.Client(protocol);
transport.Open();
Person p = new Person();
p.Name="neohope";
Console.WriteLine(client.SayHelloTo(p));
Console.WriteLine(client.Add(1, 2));
transport.Close();
}
}
}
3、编译运行
看一眼下面的框架,你就会发现,Thrift框架其实与CORBA、ICE很相似。对使用者来说,最大的不同,估计是Thrift用一个可执行文件,生成各种各样的代码咯(别告诉我你信了)。

Thrift是典型CS架构,与ICE、CORBA相同,Thrift帮我们处理的底层的网络通信及服务定位,我们只需要告诉Thrift服务在哪里,需要哪个服务,调用参数是什么,然后就坐等处理结果就好咯。
使用Thrift的时候,首先要先下载Thrift的开发包,分两部分。
Thrift
一个是一个EXE文件,适用于从IDL描述文件,生成各类语言代码的。
第二个是源码压缩包,用于编译自己所需语言的支持包。
受用Thrift之前,要先编译需要的语言支持包,我这里用到了C#和Java。
Java包,直接到路径lib/java下,执行ant命令就好了
C#包,直接到路径lib/csharp/src下,用VS编译Thrift.sln就好了
使用Thrift的时候,首先要用IDL语言,定义一个接口描述文件,比如我自己写了一个很简单的接口。
JustATest.thrift
struct Person {
1: string name
2: i32 age
3: string sex
4: string address
}
service JustATest {
string SayHelloTo(1:Person person);
i32 Add(1:i32 a,2:i32 b);
}
然后用语言的转化工具,将接口描述文件,转化为对应语言。
#生成java代码,会有两个文件 thrift -gen java JustATest.thrift #生成C#代码,会有两个文件 thrift -gen csharp JustATest.thrift
在对应的项目中包含这些文件及所需要的库文件(jar、dll),就可以开工了。