├── src ├── main │ ├── webapp │ │ ├── index.jsp │ │ └── WEB-INF │ │ │ └── web.xml │ ├── resources │ │ ├── rpc.properties │ │ ├── client-spring.xml │ │ ├── server-spring.xml │ │ ├── spring.xml │ │ ├── springmvc-config.xml │ │ ├── applicationContext.xml │ │ └── logback.xml │ └── java │ │ └── com │ │ └── tianjunwei │ │ ├── rpc │ │ ├── ServicesHandler.java │ │ ├── HelloHandler.java │ │ ├── TestClient.java │ │ └── XmlRpcServicesServlet.java │ │ ├── socketrpc │ │ ├── hello │ │ │ ├── HelloRpc.java │ │ │ └── HelloRpcImpl.java │ │ ├── Main.java │ │ ├── RPCProxy.java │ │ └── RPCServer.java │ │ ├── hessian │ │ ├── server │ │ │ ├── HelloService.java │ │ │ └── HelloServiceImpl.java │ │ ├── client │ │ │ ├── HelloServiceMain.java │ │ │ ├── HelloServiceControllerMain.java │ │ │ └── SpringClient.java │ │ └── serialize │ │ │ └── Main.java │ │ ├── zknettyRpc │ │ ├── client │ │ │ ├── AsyncRPCCallback.java │ │ │ ├── proxy │ │ │ │ ├── IAsyncObjectProxy.java │ │ │ │ └── ObjectProxy.java │ │ │ ├── RpcClientInitializer.java │ │ │ ├── RpcClient.java │ │ │ ├── RpcClientHandler.java │ │ │ ├── RPCFuture.java │ │ │ └── ConnectManage.java │ │ ├── registry │ │ │ ├── Constant.java │ │ │ ├── ServiceRegistry.java │ │ │ └── ServiceDiscovery.java │ │ ├── server │ │ │ ├── RpcService.java │ │ │ ├── RpcHandler.java │ │ │ └── RpcServer.java │ │ └── protocol │ │ │ ├── RpcResponse.java │ │ │ ├── RpcEncoder.java │ │ │ ├── RpcRequest.java │ │ │ ├── RpcDecoder.java │ │ │ ├── SerializationUtil.java │ │ │ └── JsonUtil.java │ │ └── nettyrpc │ │ ├── Main.java │ │ ├── ResultHandler.java │ │ ├── entity │ │ └── ClassInfo.java │ │ ├── InvokerHandler.java │ │ ├── RPCServer.java │ │ └── RPCProxy.java └── test │ ├── java │ └── com │ │ └── tianjunwei │ │ └── test │ │ ├── client │ │ ├── HelloService.java │ │ ├── HelloPersonService.java │ │ └── Person.java │ │ ├── server │ │ ├── RpcBootstrap.java │ │ ├── HelloServiceImpl.java │ │ └── HelloPersonServiceImpl.java │ │ ├── app │ │ ├── Benchmark.java │ │ ├── HelloPersonCallbackTest.java │ │ ├── BenchmarkAsync.java │ │ └── HelloServiceTest.java │ │ └── util │ │ └── JsonTest.java │ └── resources │ └── logback.xml ├── README.md └── pom.xml /src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TTRPC 2 | rpc框架学习的demo工程 3 | -------------------------------------------------------------------------------- /src/main/resources/rpc.properties: -------------------------------------------------------------------------------- 1 | # zookeeper server 2 | registry.address=127.0.0.1:2181 3 | # rpc server 4 | server.address=127.0.0.1:18866 -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/rpc/ServicesHandler.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.rpc; 2 | 3 | public interface ServicesHandler { 4 | public String execute(String str); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/socketrpc/hello/HelloRpc.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.socketrpc.hello; 2 | 3 | public interface HelloRpc { 4 | String hello(String name); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/hessian/server/HelloService.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.hessian.server; 2 | 3 | public interface HelloService { 4 | public String helloWorld(String message); 5 | } 6 | -------------------------------------------------------------------------------- /src/test/java/com/tianjunwei/test/client/HelloService.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.test.client; 2 | 3 | public interface HelloService { 4 | 5 | String hello(String name); 6 | 7 | String hello(Person person); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/zknettyRpc/client/AsyncRPCCallback.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.zknettyRpc.client; 2 | 3 | public interface AsyncRPCCallback { 4 | 5 | void success(Object result); 6 | 7 | void fail(Exception e); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/rpc/HelloHandler.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.rpc; 2 | 3 | public class HelloHandler implements ServicesHandler{ 4 | 5 | @Override 6 | public String execute(String str) { 7 | return "hello "+str+"!"; 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/socketrpc/hello/HelloRpcImpl.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.socketrpc.hello; 2 | 3 | public class HelloRpcImpl implements HelloRpc { 4 | 5 | @Override 6 | public String hello(String name) { 7 | return "hello "+name; 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/hessian/server/HelloServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.hessian.server; 2 | 3 | public class HelloServiceImpl implements HelloService{ 4 | 5 | @Override 6 | public String helloWorld(String message) { 7 | return "hello," + message; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/test/java/com/tianjunwei/test/client/HelloPersonService.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.test.client; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by luxiaoxun on 2016-03-10. 7 | */ 8 | public interface HelloPersonService { 9 | List GetTestPerson(String name,int num); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/zknettyRpc/registry/Constant.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.zknettyRpc.registry; 2 | 3 | 4 | public interface Constant { 5 | 6 | int ZK_SESSION_TIMEOUT = 5000; 7 | 8 | String ZK_REGISTRY_PATH = "/registry"; 9 | String ZK_DATA_PATH = ZK_REGISTRY_PATH + "/data"; 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/zknettyRpc/client/proxy/IAsyncObjectProxy.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.zknettyRpc.client.proxy; 2 | 3 | import com.tianjunwei.zknettyRpc.client.RPCFuture; 4 | 5 | /** 6 | * Created by luxiaoxun on 2016/3/16. 7 | */ 8 | public interface IAsyncObjectProxy { 9 | public RPCFuture call(String funcName, Object... args); 10 | } -------------------------------------------------------------------------------- /src/test/java/com/tianjunwei/test/server/RpcBootstrap.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.test.server; 2 | 3 | import org.springframework.context.support.ClassPathXmlApplicationContext; 4 | 5 | public class RpcBootstrap { 6 | 7 | public static void main(String[] args) { 8 | new ClassPathXmlApplicationContext("server-spring.xml"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/nettyrpc/Main.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.nettyrpc; 2 | 3 | import com.tianjunwei.socketrpc.hello.HelloRpc; 4 | import com.tianjunwei.socketrpc.hello.HelloRpcImpl; 5 | 6 | public class Main { 7 | public static void main(String [] args){ 8 | HelloRpc helloRpc = new HelloRpcImpl(); 9 | helloRpc = RPCProxy.create(helloRpc); 10 | System.err.println(helloRpc.hello("rpc")); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/socketrpc/Main.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.socketrpc; 2 | 3 | import com.tianjunwei.socketrpc.hello.HelloRpc; 4 | import com.tianjunwei.socketrpc.hello.HelloRpcImpl; 5 | 6 | public class Main { 7 | 8 | public static void main(String [] args){ 9 | HelloRpc helloRpc = new HelloRpcImpl(); 10 | helloRpc = RPCProxy.create(helloRpc); 11 | System.err.println(helloRpc.hello("rpc")); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/zknettyRpc/server/RpcService.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.zknettyRpc.server; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | import org.springframework.stereotype.Component; 8 | 9 | 10 | @Target({ElementType.TYPE}) 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Component 13 | public @interface RpcService { 14 | Class value(); 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/com/tianjunwei/test/server/HelloServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.test.server; 2 | 3 | import com.tianjunwei.test.client.HelloService; 4 | import com.tianjunwei.test.client.Person; 5 | import com.tianjunwei.zknettyRpc.server.RpcService; 6 | 7 | @RpcService(HelloService.class) 8 | public class HelloServiceImpl implements HelloService { 9 | 10 | @Override 11 | public String hello(String name) { 12 | return "Hello! " + name; 13 | } 14 | 15 | @Override 16 | public String hello(Person person) { 17 | return "Hello! " + person.getFirstName() + " " + person.getLastName(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/hessian/client/HelloServiceMain.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.hessian.client; 2 | 3 | import java.net.MalformedURLException; 4 | 5 | import com.caucho.hessian.client.HessianProxyFactory; 6 | import com.tianjunwei.hessian.server.HelloService; 7 | 8 | public class HelloServiceMain { 9 | 10 | public static void main(String [] args) throws MalformedURLException{ 11 | String url = "http://localhost:8080/hessian"; 12 | System.out.println(url); 13 | HessianProxyFactory factory = new HessianProxyFactory(); 14 | HelloService helloService = (HelloService) factory.create(HelloService.class, url); 15 | System.out.println(helloService.helloWorld("jimmy")); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/hessian/client/HelloServiceControllerMain.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.hessian.client; 2 | 3 | import java.net.MalformedURLException; 4 | 5 | import com.caucho.hessian.client.HessianProxyFactory; 6 | import com.tianjunwei.hessian.server.HelloService; 7 | 8 | public class HelloServiceControllerMain { 9 | 10 | public static void main(String [] args) throws MalformedURLException{ 11 | String url = "http://localhost/hessian.action"; 12 | System.out.println(url); 13 | HessianProxyFactory factory = new HessianProxyFactory(); 14 | HelloService helloService = (HelloService) factory.create(HelloService.class, url); 15 | System.out.println(helloService.helloWorld("world")); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/hessian/client/SpringClient.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.hessian.client; 2 | 3 | import org.springframework.context.ApplicationContext; 4 | import org.springframework.context.support.ClassPathXmlApplicationContext; 5 | 6 | import com.tianjunwei.hessian.server.HelloService; 7 | 8 | public class SpringClient { 9 | 10 | @SuppressWarnings("resource") 11 | public static void main(String[] args) { 12 | ApplicationContext contex = new ClassPathXmlApplicationContext( 13 | "applicationContext.xml"); 14 | // 获得客户端的Hessian代理工厂bean 15 | HelloService helloService = (HelloService) contex.getBean("clientSpring"); 16 | System.out.println(helloService.helloWorld("world")); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/tianjunwei/test/server/HelloPersonServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.test.server; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.tianjunwei.test.client.HelloPersonService; 7 | import com.tianjunwei.test.client.Person; 8 | import com.tianjunwei.zknettyRpc.server.RpcService; 9 | 10 | /** 11 | * Created by luxiaoxun on 2016-03-10. 12 | */ 13 | @RpcService(HelloPersonService.class) 14 | public class HelloPersonServiceImpl implements HelloPersonService { 15 | 16 | @Override 17 | public List GetTestPerson(String name, int num) { 18 | List persons = new ArrayList<>(num); 19 | for (int i = 0; i < num; ++i) { 20 | persons.add(new Person(Integer.toString(i), name)); 21 | } 22 | return persons; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/nettyrpc/ResultHandler.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.nettyrpc; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.ChannelInboundHandlerAdapter; 5 | 6 | public class ResultHandler extends ChannelInboundHandlerAdapter { 7 | 8 | private Object response; 9 | 10 | public Object getResponse() { 11 | return response; 12 | } 13 | 14 | @Override 15 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 16 | response=msg; 17 | System.out.println("client接收到服务器返回的消息:" + msg); 18 | } 19 | 20 | @Override 21 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 22 | System.out.println("client exception is general"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/zknettyRpc/protocol/RpcResponse.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.zknettyRpc.protocol; 2 | 3 | 4 | public class RpcResponse { 5 | 6 | private String requestId; 7 | private String error; 8 | private Object result; 9 | 10 | public boolean isError() { 11 | return error != null; 12 | } 13 | 14 | public String getRequestId() { 15 | return requestId; 16 | } 17 | 18 | public void setRequestId(String requestId) { 19 | this.requestId = requestId; 20 | } 21 | 22 | public String getError() { 23 | return error; 24 | } 25 | 26 | public void setError(String error) { 27 | this.error = error; 28 | } 29 | 30 | public Object getResult() { 31 | return result; 32 | } 33 | 34 | public void setResult(Object result) { 35 | this.result = result; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/zknettyRpc/protocol/RpcEncoder.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.zknettyRpc.protocol; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.handler.codec.MessageToByteEncoder; 6 | 7 | /** 8 | * RPC Encoder 9 | * @author huangyong 10 | */ 11 | public class RpcEncoder extends MessageToByteEncoder { 12 | 13 | private Class genericClass; 14 | 15 | public RpcEncoder(Class genericClass) { 16 | this.genericClass = genericClass; 17 | } 18 | 19 | @Override 20 | public void encode(ChannelHandlerContext ctx, Object in, ByteBuf out) throws Exception { 21 | if (genericClass.isInstance(in)) { 22 | byte[] data = SerializationUtil.serialize(in); 23 | //byte[] data = JsonUtil.serialize(in); // Not use this, have some bugs 24 | out.writeInt(data.length); 25 | out.writeBytes(data); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/resources/client-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/nettyrpc/entity/ClassInfo.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.nettyrpc.entity; 2 | 3 | import java.io.Serializable; 4 | 5 | public class ClassInfo implements Serializable { 6 | 7 | private static final long serialVersionUID = -8970942815543515064L; 8 | 9 | private String className;//类名 10 | private String methodName;//函数名称 11 | private Class[] types;//参数类型 12 | private Object[] objects;//参数列表 13 | public String getClassName() { 14 | return className; 15 | } 16 | public void setClassName(String className) { 17 | this.className = className; 18 | } 19 | public String getMethodName() { 20 | return methodName; 21 | } 22 | public void setMethodName(String methodName) { 23 | this.methodName = methodName; 24 | } 25 | public Class[] getTypes() { 26 | return types; 27 | } 28 | public void setTypes(Class[] types) { 29 | this.types = types; 30 | } 31 | public Object[] getObjects() { 32 | return objects; 33 | } 34 | public void setObjects(Object[] objects) { 35 | this.objects = objects; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/zknettyRpc/client/RpcClientInitializer.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.zknettyRpc.client; 2 | 3 | import com.tianjunwei.zknettyRpc.protocol.RpcDecoder; 4 | import com.tianjunwei.zknettyRpc.protocol.RpcEncoder; 5 | import com.tianjunwei.zknettyRpc.protocol.RpcRequest; 6 | import com.tianjunwei.zknettyRpc.protocol.RpcResponse; 7 | 8 | import io.netty.channel.ChannelInitializer; 9 | import io.netty.channel.ChannelPipeline; 10 | import io.netty.channel.socket.SocketChannel; 11 | import io.netty.handler.codec.LengthFieldBasedFrameDecoder; 12 | 13 | /** 14 | * Created by luxiaoxun on 2016-03-16. 15 | */ 16 | public class RpcClientInitializer extends ChannelInitializer { 17 | @Override 18 | protected void initChannel(SocketChannel socketChannel) throws Exception { 19 | ChannelPipeline cp = socketChannel.pipeline(); 20 | cp.addLast(new RpcEncoder(RpcRequest.class)); 21 | cp.addLast(new LengthFieldBasedFrameDecoder(65536, 0, 4, 0, 0)); 22 | cp.addLast(new RpcDecoder(RpcResponse.class)); 23 | cp.addLast(new RpcClientHandler()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/resources/server-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/hessian/serialize/Main.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.hessian.serialize; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.IOException; 6 | 7 | import com.caucho.hessian.io.HessianInput; 8 | import com.caucho.hessian.io.HessianOutput; 9 | 10 | public class Main { 11 | 12 | public static void main(String[] args) throws IOException { 13 | 14 | String teString = " hello world"; 15 | byte b[] = serialize(teString); 16 | 17 | teString = (String) deserialize(b); 18 | System.out.println(teString); 19 | 20 | } 21 | 22 | public static byte[] serialize(Object obj) throws IOException{ 23 | if(obj==null) throw new NullPointerException(); 24 | ByteArrayOutputStream os = new ByteArrayOutputStream(); 25 | HessianOutput ho = new HessianOutput(os); 26 | ho.writeObject(obj); 27 | return os.toByteArray(); 28 | } 29 | 30 | public static Object deserialize(byte[] by) throws IOException{ 31 | if(by==null) throw new NullPointerException(); 32 | ByteArrayInputStream is = new ByteArrayInputStream(by); 33 | HessianInput hi = new HessianInput(is); 34 | return hi.readObject(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/com/tianjunwei/test/client/Person.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.test.client; 2 | 3 | public class Person { 4 | 5 | private String firstName; 6 | private String lastName; 7 | 8 | public Person() { 9 | } 10 | 11 | public Person(String firstName, String lastName) { 12 | this.firstName = firstName; 13 | this.lastName = lastName; 14 | } 15 | 16 | public String getFirstName() { 17 | return firstName; 18 | } 19 | 20 | public void setFirstName(String firstName) { 21 | this.firstName = firstName; 22 | } 23 | 24 | public String getLastName() { 25 | return lastName; 26 | } 27 | 28 | public void setLastName(String lastName) { 29 | this.lastName = lastName; 30 | } 31 | 32 | @Override 33 | public String toString(){ 34 | return firstName + " " + lastName; 35 | } 36 | 37 | @Override 38 | public int hashCode() { 39 | return this.firstName.hashCode()^this.lastName.hashCode(); 40 | } 41 | 42 | @Override 43 | public boolean equals(Object obj) { 44 | if(!(obj instanceof Person) ) return false; 45 | Person p = (Person)obj; 46 | return this.firstName.equals(p.firstName) && this.lastName.equals(p.lastName); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/zknettyRpc/protocol/RpcRequest.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.zknettyRpc.protocol; 2 | 3 | 4 | public class RpcRequest { 5 | 6 | private String requestId; 7 | private String className; 8 | private String methodName; 9 | private Class[] parameterTypes; 10 | private Object[] parameters; 11 | 12 | public String getRequestId() { 13 | return requestId; 14 | } 15 | 16 | public void setRequestId(String requestId) { 17 | this.requestId = requestId; 18 | } 19 | 20 | public String getClassName() { 21 | return className; 22 | } 23 | 24 | public void setClassName(String className) { 25 | this.className = className; 26 | } 27 | 28 | public String getMethodName() { 29 | return methodName; 30 | } 31 | 32 | public void setMethodName(String methodName) { 33 | this.methodName = methodName; 34 | } 35 | 36 | public Class[] getParameterTypes() { 37 | return parameterTypes; 38 | } 39 | 40 | public void setParameterTypes(Class[] parameterTypes) { 41 | this.parameterTypes = parameterTypes; 42 | } 43 | 44 | public Object[] getParameters() { 45 | return parameters; 46 | } 47 | 48 | public void setParameters(Object[] parameters) { 49 | this.parameters = parameters; 50 | } 51 | } -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/zknettyRpc/protocol/RpcDecoder.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.zknettyRpc.protocol; 2 | 3 | import java.util.List; 4 | 5 | import io.netty.buffer.ByteBuf; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.handler.codec.ByteToMessageDecoder; 8 | 9 | /** 10 | * RPC Decoder 11 | * @author huangyong 12 | */ 13 | public class RpcDecoder extends ByteToMessageDecoder { 14 | 15 | private Class genericClass; 16 | 17 | public RpcDecoder(Class genericClass) { 18 | this.genericClass = genericClass; 19 | } 20 | 21 | @Override 22 | public final void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { 23 | if (in.readableBytes() < 4) { 24 | return; 25 | } 26 | in.markReaderIndex(); 27 | int dataLength = in.readInt(); 28 | /*if (dataLength <= 0) { 29 | ctx.close(); 30 | }*/ 31 | if (in.readableBytes() < dataLength) { 32 | in.resetReaderIndex(); 33 | return; 34 | } 35 | byte[] data = new byte[dataLength]; 36 | in.readBytes(data); 37 | 38 | Object obj = SerializationUtil.deserialize(data, genericClass); 39 | //Object obj = JsonUtil.deserialize(data,genericClass); // Not use this, have some bugs 40 | out.add(obj); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/rpc/TestClient.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.rpc; 2 | 3 | import java.net.MalformedURLException; 4 | import java.net.URL; 5 | import java.util.Vector; 6 | 7 | import org.apache.xmlrpc.XmlRpcException; 8 | import org.apache.xmlrpc.client.XmlRpcClient; 9 | import org.apache.xmlrpc.client.XmlRpcClientConfigImpl; 10 | 11 | public class TestClient { 12 | 13 | /** 14 | * @param args 15 | */ 16 | public static void main(String[] args) { 17 | try { 18 | //配置客户端 19 | XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl(); 20 | //设置服务器端地址 21 | config.setServerURL(new URL("http://localhost:8080/HelloHandler")); 22 | //创建XmlRpc客户端 23 | XmlRpcClient client = new XmlRpcClient(); 24 | //绑定以上设置 25 | client.setConfig(config); 26 | //创建参数列表 27 | Vector params = new Vector(); 28 | params.addElement("flyoung"); 29 | //执行XML-RPC 请求 30 | String result =(String) client.execute("HelloHandler.execute", params); 31 | System.out.println("result:"+result); 32 | } catch (MalformedURLException e) { 33 | e.printStackTrace(); 34 | } catch (XmlRpcException e) { 35 | e.printStackTrace(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/resources/spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/nettyrpc/InvokerHandler.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.nettyrpc; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | import com.tianjunwei.nettyrpc.entity.ClassInfo; 7 | 8 | import io.netty.channel.ChannelHandlerContext; 9 | import io.netty.channel.ChannelInboundHandlerAdapter; 10 | 11 | public class InvokerHandler extends ChannelInboundHandlerAdapter { 12 | public static ConcurrentHashMap classMap = new ConcurrentHashMap(); 13 | @Override 14 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 15 | ClassInfo classInfo = (ClassInfo)msg; 16 | Object claszz = null; 17 | //用于记录反射获得类,这样可以提高性能 18 | if(!classMap.containsKey(classInfo.getClassName())){ 19 | try { 20 | claszz = Class.forName(classInfo.getClassName()).newInstance(); 21 | classMap.put(classInfo.getClassName(), claszz); 22 | } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { 23 | e.printStackTrace(); 24 | } 25 | }else { 26 | claszz = classMap.get(classInfo.getClassName()); 27 | } 28 | Method method = claszz.getClass().getMethod(classInfo.getMethodName(), classInfo.getTypes()); 29 | Object result = method.invoke(claszz, classInfo.getObjects()); 30 | ctx.write(result); 31 | ctx.flush(); 32 | ctx.close(); 33 | } 34 | @Override 35 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 36 | cause.printStackTrace(); 37 | ctx.close(); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/zknettyRpc/client/RpcClient.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.zknettyRpc.client; 2 | 3 | import java.lang.reflect.Proxy; 4 | import java.util.concurrent.ArrayBlockingQueue; 5 | import java.util.concurrent.ThreadPoolExecutor; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import com.tianjunwei.zknettyRpc.client.proxy.IAsyncObjectProxy; 9 | import com.tianjunwei.zknettyRpc.client.proxy.ObjectProxy; 10 | import com.tianjunwei.zknettyRpc.registry.ServiceDiscovery; 11 | 12 | 13 | public class RpcClient { 14 | 15 | private String serverAddress; 16 | private ServiceDiscovery serviceDiscovery; 17 | private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(16, 16, 600L, TimeUnit.SECONDS, new ArrayBlockingQueue(65536)); 18 | 19 | public RpcClient(String serverAddress) { 20 | this.serverAddress = serverAddress; 21 | } 22 | 23 | public RpcClient(ServiceDiscovery serviceDiscovery) { 24 | this.serviceDiscovery = serviceDiscovery; 25 | } 26 | 27 | @SuppressWarnings("unchecked") 28 | public static T create(Class interfaceClass) { 29 | return (T) Proxy.newProxyInstance( 30 | interfaceClass.getClassLoader(), 31 | new Class[]{interfaceClass}, 32 | new ObjectProxy(interfaceClass) 33 | ); 34 | } 35 | 36 | public static IAsyncObjectProxy createAsync(Class interfaceClass) { 37 | return new ObjectProxy(interfaceClass); 38 | } 39 | 40 | public static void submit(Runnable task){ 41 | threadPoolExecutor.submit(task); 42 | } 43 | 44 | public void stop() { 45 | threadPoolExecutor.shutdown(); 46 | serviceDiscovery.stop(); 47 | ConnectManage.getInstance().stop(); 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/main/resources/springmvc-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/socketrpc/RPCProxy.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.socketrpc; 2 | 3 | import java.io.ObjectInputStream; 4 | import java.io.ObjectOutputStream; 5 | import java.lang.reflect.InvocationHandler; 6 | import java.lang.reflect.Method; 7 | import java.lang.reflect.Proxy; 8 | import java.net.Socket; 9 | 10 | public class RPCProxy { 11 | 12 | @SuppressWarnings("unchecked") 13 | public static T create(Object target){ 14 | 15 | return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), new InvocationHandler(){ 16 | 17 | @Override 18 | public Object invoke(Object proxy, Method method, Object[] args) 19 | throws Throwable { 20 | Socket socket = new Socket("localhost", 8080); 21 | ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream()); 22 | try { 23 | output.writeUTF(target.getClass().getName()); 24 | output.writeUTF(method.getName()); 25 | output.writeObject(method.getParameterTypes()); 26 | output.writeObject(args); 27 | ObjectInputStream input = new ObjectInputStream(socket.getInputStream()); 28 | try { 29 | Object result = input.readObject(); 30 | if (result instanceof Throwable) { 31 | throw (Throwable) result; 32 | } 33 | return result; 34 | } finally { 35 | input.close(); 36 | } 37 | } finally { 38 | output.close(); 39 | socket.close(); 40 | } 41 | } 42 | 43 | }); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/com/tianjunwei/test/app/Benchmark.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.test.app; 2 | 3 | import com.tianjunwei.test.client.HelloService; 4 | import com.tianjunwei.zknettyRpc.client.RpcClient; 5 | import com.tianjunwei.zknettyRpc.registry.ServiceDiscovery; 6 | 7 | /** 8 | * Created by luxiaoxun on 2016-03-11. 9 | */ 10 | public class Benchmark { 11 | 12 | public static void main(String[] args) throws InterruptedException { 13 | 14 | ServiceDiscovery serviceDiscovery = new ServiceDiscovery("127.0.0.1:2181"); 15 | final RpcClient rpcClient = new RpcClient(serviceDiscovery); 16 | 17 | int threadNum = 10; 18 | final int requestNum = 100; 19 | Thread[] threads = new Thread[threadNum]; 20 | 21 | long startTime = System.currentTimeMillis(); 22 | //benchmark for sync call 23 | for(int i = 0; i < threadNum; ++i){ 24 | threads[i] = new Thread(new Runnable(){ 25 | @Override 26 | public void run() { 27 | for (int i = 0; i < requestNum; i++) { 28 | final HelloService syncClient = rpcClient.create(HelloService.class); 29 | String result = syncClient.hello(Integer.toString(i)); 30 | if (!result.equals("Hello! " + i)) 31 | System.out.print("error = " + result); 32 | } 33 | } 34 | }); 35 | threads[i].start(); 36 | } 37 | for(int i=0; i persons = (List) result; 31 | for (int i = 0; i < persons.size(); ++i) { 32 | System.out.println(persons.get(i)); 33 | } 34 | countDownLatch.countDown(); 35 | } 36 | 37 | @Override 38 | public void fail(Exception e) { 39 | System.out.println(e); 40 | countDownLatch.countDown(); 41 | } 42 | }); 43 | 44 | } catch (Exception e) { 45 | System.out.println(e); 46 | } 47 | 48 | try { 49 | countDownLatch.await(); 50 | } catch (InterruptedException e) { 51 | e.printStackTrace(); 52 | } 53 | 54 | rpcClient.stop(); 55 | 56 | System.out.println("End"); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/rpc/XmlRpcServicesServlet.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.rpc; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.ServletConfig; 6 | import javax.servlet.ServletException; 7 | import javax.servlet.http.HttpServlet; 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | 11 | import org.apache.xmlrpc.XmlRpcException; 12 | import org.apache.xmlrpc.server.PropertyHandlerMapping; 13 | import org.apache.xmlrpc.server.XmlRpcServerConfigImpl; 14 | import org.apache.xmlrpc.webserver.XmlRpcServletServer; 15 | 16 | public class XmlRpcServicesServlet extends HttpServlet { 17 | /** 18 | * 19 | */ 20 | private static final long serialVersionUID = -2994076601912002234L; 21 | 22 | private XmlRpcServletServer server; 23 | @Override 24 | public void init(ServletConfig config) throws ServletException { 25 | super.init(config); 26 | try { 27 | //创建XmlRpcServletServer对象 28 | server = new XmlRpcServletServer(); 29 | 30 | //set up handler mapping of XmlRpcServletServer object 31 | PropertyHandlerMapping pmp = new PropertyHandlerMapping(); 32 | pmp.addHandler("HelloHandler", HelloHandler.class); 33 | server.setHandlerMapping(pmp); 34 | 35 | //more config of XmlRpcServletServer object 36 | XmlRpcServerConfigImpl serverConfig = (XmlRpcServerConfigImpl)server.getConfig(); 37 | serverConfig.setEnabledForExtensions(true); 38 | serverConfig.setContentLengthOptional(false); 39 | } catch (XmlRpcException e) { 40 | // TODO Auto-generated catch block 41 | e.printStackTrace(); 42 | } 43 | } 44 | 45 | 46 | @Override 47 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) 48 | throws ServletException, IOException { 49 | 50 | server.execute(req, resp); 51 | } 52 | 53 | @Override 54 | protected void doPost(HttpServletRequest req, HttpServletResponse resp) 55 | throws ServletException, IOException { 56 | 57 | server.execute(req, resp); 58 | } 59 | 60 | 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/zknettyRpc/protocol/SerializationUtil.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.zknettyRpc.protocol; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | 7 | import org.springframework.objenesis.Objenesis; 8 | import org.springframework.objenesis.ObjenesisStd; 9 | 10 | import com.dyuproject.protostuff.LinkedBuffer; 11 | import com.dyuproject.protostuff.ProtostuffIOUtil; 12 | import com.dyuproject.protostuff.Schema; 13 | import com.dyuproject.protostuff.runtime.RuntimeSchema; 14 | 15 | /** 16 | * Serialization Util(Based on Protostuff) 17 | * @author huangyong 18 | */ 19 | public class SerializationUtil { 20 | 21 | private static Map, Schema> cachedSchema = new ConcurrentHashMap<>(); 22 | 23 | private static Objenesis objenesis = new ObjenesisStd(true); 24 | 25 | private SerializationUtil() { 26 | } 27 | 28 | @SuppressWarnings("unchecked") 29 | private static Schema getSchema(Class cls) { 30 | Schema schema = (Schema) cachedSchema.get(cls); 31 | if (schema == null) { 32 | schema = RuntimeSchema.createFrom(cls); 33 | if (schema != null) { 34 | cachedSchema.put(cls, schema); 35 | } 36 | } 37 | return schema; 38 | } 39 | 40 | /** 41 | * 序列化(对象 -> 字节数组) 42 | */ 43 | @SuppressWarnings("unchecked") 44 | public static byte[] serialize(T obj) { 45 | Class cls = (Class) obj.getClass(); 46 | LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE); 47 | try { 48 | Schema schema = getSchema(cls); 49 | return ProtostuffIOUtil.toByteArray(obj, schema, buffer); 50 | } catch (Exception e) { 51 | throw new IllegalStateException(e.getMessage(), e); 52 | } finally { 53 | buffer.clear(); 54 | } 55 | } 56 | 57 | /** 58 | * 反序列化(字节数组 -> 对象) 59 | */ 60 | public static T deserialize(byte[] data, Class cls) { 61 | try { 62 | T message = (T) objenesis.newInstance(cls); 63 | Schema schema = getSchema(cls); 64 | ProtostuffIOUtil.mergeFrom(data, message, schema); 65 | return message; 66 | } catch (Exception e) { 67 | throw new IllegalStateException(e.getMessage(), e); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/resources/applicationContext.xml: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | http://localhost:8080/hessian 37 | 38 | 39 | 40 | com.tianjunwei.hessian.server.HelloService 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/test/java/com/tianjunwei/test/app/BenchmarkAsync.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.test.app; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import com.tianjunwei.hessian.server.HelloService; 6 | import com.tianjunwei.zknettyRpc.client.RPCFuture; 7 | import com.tianjunwei.zknettyRpc.client.RpcClient; 8 | import com.tianjunwei.zknettyRpc.client.proxy.IAsyncObjectProxy; 9 | import com.tianjunwei.zknettyRpc.registry.ServiceDiscovery; 10 | 11 | /** 12 | * Created by luxiaoxun on 2016/3/16. 13 | */ 14 | public class BenchmarkAsync { 15 | public static void main(String[] args) throws InterruptedException { 16 | ServiceDiscovery serviceDiscovery = new ServiceDiscovery("127.0.0.1:2181"); 17 | final RpcClient rpcClient = new RpcClient(serviceDiscovery); 18 | 19 | int threadNum = 10; 20 | final int requestNum = 20; 21 | Thread[] threads = new Thread[threadNum]; 22 | 23 | long startTime = System.currentTimeMillis(); 24 | //benchmark for async call 25 | for (int i = 0; i < threadNum; ++i) { 26 | threads[i] = new Thread(new Runnable() { 27 | @Override 28 | public void run() { 29 | for (int i = 0; i < requestNum; i++) { 30 | try { 31 | IAsyncObjectProxy client = rpcClient.createAsync(HelloService.class); 32 | RPCFuture helloFuture = client.call("hello", Integer.toString(i)); 33 | String result = (String) helloFuture.get(3000, TimeUnit.MILLISECONDS); 34 | //System.out.println(result); 35 | if (!result.equals("Hello! " + i)) 36 | System.out.println("error = " + result); 37 | } catch (Exception e) { 38 | System.out.println(e); 39 | } 40 | } 41 | } 42 | }); 43 | threads[i].start(); 44 | } 45 | for (int i = 0; i < threads.length; i++) { 46 | threads[i].join(); 47 | } 48 | long timeCost = (System.currentTimeMillis() - startTime); 49 | String msg = String.format("Async call total-time-cost:%sms, req/s=%s", timeCost, ((double) (requestNum * threadNum)) / timeCost * 1000); 50 | System.out.println(msg); 51 | 52 | rpcClient.stop(); 53 | 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | contextConfigLocation 8 | 9 | classpath:applicationContext.xml 10 | 11 | 12 | 13 | org.springframework.web.context.ContextLoaderListener 14 | 15 | 16 | springmvc 17 | 18 | org.springframework.web.servlet.DispatcherServlet 19 | 20 | 21 | contextConfigLocation 22 | classpath:springmvc-config.xml 23 | 24 | 1 25 | 26 | 27 | 28 | springmvc 29 | *.action 30 | 31 | 32 | 33 | index.jsp 34 | 35 | 36 | XmlRpcServer 37 | com.tianjunwei.rpc.XmlRpcServicesServlet 38 | 39 | 40 | XmlRpcServer 41 | /HelloHandler 42 | 43 | 44 | 45 | 46 | hessian-service 47 | 48 | com.caucho.hessian.server.HessianServlet 49 | 50 | 51 | home-class 52 | 53 | 54 | com.tianjunwei.hessian.server.HelloServiceImpl 55 | 56 | 57 | 58 | home-api 59 | 60 | com.tianjunwei.hessian.server.HelloService 61 | 62 | 63 | 64 | 65 | 66 | hessian-service 67 | /hessian 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/zknettyRpc/client/RpcClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.zknettyRpc.client; 2 | 3 | import java.net.SocketAddress; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import com.tianjunwei.zknettyRpc.protocol.RpcRequest; 10 | import com.tianjunwei.zknettyRpc.protocol.RpcResponse; 11 | 12 | import io.netty.buffer.Unpooled; 13 | import io.netty.channel.Channel; 14 | import io.netty.channel.ChannelFutureListener; 15 | import io.netty.channel.ChannelHandlerContext; 16 | import io.netty.channel.SimpleChannelInboundHandler; 17 | 18 | public class RpcClientHandler extends SimpleChannelInboundHandler { 19 | private static final Logger LOGGER = LoggerFactory.getLogger(RpcClientHandler.class); 20 | 21 | private ConcurrentHashMap pendingRPC = new ConcurrentHashMap<>(); 22 | 23 | private volatile Channel channel; 24 | private SocketAddress remotePeer; 25 | 26 | public Channel getChannel() { 27 | return channel; 28 | } 29 | 30 | public SocketAddress getRemotePeer() { 31 | return remotePeer; 32 | } 33 | 34 | @Override 35 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 36 | super.channelActive(ctx); 37 | this.remotePeer = this.channel.remoteAddress(); 38 | } 39 | 40 | @Override 41 | public void channelRegistered(ChannelHandlerContext ctx) throws Exception { 42 | super.channelRegistered(ctx); 43 | this.channel = ctx.channel(); 44 | } 45 | 46 | @Override 47 | public void channelRead0(ChannelHandlerContext ctx, RpcResponse response) throws Exception { 48 | String requestId = response.getRequestId(); 49 | RPCFuture rpcFuture = pendingRPC.get(requestId); 50 | if (rpcFuture != null) { 51 | pendingRPC.remove(requestId); 52 | rpcFuture.done(response); 53 | } 54 | } 55 | 56 | @Override 57 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 58 | LOGGER.error("client caught exception", cause); 59 | ctx.close(); 60 | } 61 | 62 | public void close() { 63 | channel.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); 64 | } 65 | 66 | public RPCFuture sendRequest(RpcRequest request) { 67 | RPCFuture rpcFuture = new RPCFuture(request); 68 | pendingRPC.put(request.getRequestId(), rpcFuture); 69 | channel.writeAndFlush(request); 70 | 71 | return rpcFuture; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/nettyrpc/RPCServer.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.nettyrpc; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelOption; 7 | import io.netty.channel.ChannelPipeline; 8 | import io.netty.channel.EventLoopGroup; 9 | import io.netty.channel.nio.NioEventLoopGroup; 10 | import io.netty.channel.socket.SocketChannel; 11 | import io.netty.channel.socket.nio.NioServerSocketChannel; 12 | import io.netty.handler.codec.LengthFieldBasedFrameDecoder; 13 | import io.netty.handler.codec.LengthFieldPrepender; 14 | import io.netty.handler.codec.serialization.ClassResolvers; 15 | import io.netty.handler.codec.serialization.ObjectDecoder; 16 | import io.netty.handler.codec.serialization.ObjectEncoder; 17 | 18 | 19 | public class RPCServer { 20 | private int port; 21 | public RPCServer(int port){ 22 | this.port = port; 23 | } 24 | public void start(){ 25 | EventLoopGroup bossGroup = new NioEventLoopGroup(); 26 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 27 | 28 | try { 29 | ServerBootstrap serverBootstrap = new ServerBootstrap().group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) 30 | .localAddress(port).childHandler(new ChannelInitializer() { 31 | 32 | @Override 33 | protected void initChannel(SocketChannel ch) throws Exception { 34 | ChannelPipeline pipeline = ch.pipeline(); 35 | pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4)); 36 | pipeline.addLast(new LengthFieldPrepender(4)); 37 | pipeline.addLast("encoder", new ObjectEncoder()); 38 | pipeline.addLast("decoder", new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null))); 39 | pipeline.addLast(new InvokerHandler()); 40 | } 41 | }).option(ChannelOption.SO_BACKLOG, 128) 42 | .childOption(ChannelOption.SO_KEEPALIVE, true); 43 | ChannelFuture future = serverBootstrap.bind(port).sync(); 44 | System.out.println("Server start listen at " + port ); 45 | future.channel().closeFuture().sync(); 46 | } catch (Exception e) { 47 | bossGroup.shutdownGracefully(); 48 | workerGroup.shutdownGracefully(); 49 | } 50 | } 51 | public static void main(String[] args) throws Exception { 52 | int port; 53 | if (args.length > 0) { 54 | port = Integer.parseInt(args[0]); 55 | } else { 56 | port = 8080; 57 | } 58 | new RPCServer(port).start(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/socketrpc/RPCServer.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.socketrpc; 2 | 3 | import java.io.IOException; 4 | import java.io.ObjectInputStream; 5 | import java.io.ObjectOutputStream; 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | import java.net.ServerSocket; 9 | import java.net.Socket; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | /** 12 | * 服务端 13 | * @author tianjunwei 14 | */ 15 | public class RPCServer { 16 | 17 | public static ConcurrentHashMap classMap = new ConcurrentHashMap(); 18 | 19 | public static void main(String [] args) throws Exception{ 20 | System.err.println("server start"); 21 | RPCServer.invoker(8080); 22 | } 23 | @SuppressWarnings("resource") 24 | public static void invoker(int port) throws Exception{ 25 | 26 | ServerSocket server = new ServerSocket(port); 27 | for(;;){ 28 | try{ 29 | final Socket socket = server.accept(); 30 | new Thread(new Runnable() { 31 | ObjectOutputStream output = null; 32 | @Override 33 | public void run() { 34 | try{ 35 | try { 36 | output = new ObjectOutputStream(socket.getOutputStream()); 37 | ObjectInputStream input = new ObjectInputStream(socket.getInputStream()); 38 | String className = input.readUTF(); 39 | String methodName = input.readUTF(); 40 | Class[] parameterTypes = (Class[])input.readObject(); 41 | Object[] arguments = (Object[])input.readObject(); 42 | Object claszz = null; 43 | if(!classMap.containsKey(className)){ 44 | try { 45 | claszz = Class.forName(className).newInstance(); 46 | classMap.put(className, claszz); 47 | } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { 48 | e.printStackTrace(); 49 | } 50 | }else { 51 | claszz = classMap.get(className); 52 | } 53 | Method method = claszz.getClass().getMethod(methodName, parameterTypes); 54 | Object result = method.invoke(claszz, arguments); 55 | output.writeObject(result); 56 | } catch (IOException | ClassNotFoundException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { 57 | output.writeObject(e); 58 | }finally { 59 | output.close(); 60 | } 61 | }catch(Exception e){ 62 | e.printStackTrace(); 63 | }finally { 64 | try { 65 | socket.close(); 66 | } catch (IOException e) { 67 | e.printStackTrace(); 68 | } 69 | } 70 | } 71 | }).start(); 72 | }catch (Exception e) { 73 | e.printStackTrace(); 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/zknettyRpc/registry/ServiceRegistry.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.tianjunwei.zknettyRpc.registry; 5 | 6 | import java.io.IOException; 7 | import java.util.concurrent.CountDownLatch; 8 | import org.apache.zookeeper.CreateMode; 9 | import org.apache.zookeeper.KeeperException; 10 | import org.apache.zookeeper.WatchedEvent; 11 | import org.apache.zookeeper.Watcher; 12 | import org.apache.zookeeper.ZooDefs; 13 | import org.apache.zookeeper.ZooKeeper; 14 | import org.apache.zookeeper.data.Stat; 15 | import org.slf4j.Logger; 16 | import org.slf4j.LoggerFactory; 17 | 18 | /** 19 | * 20 | */ 21 | public class ServiceRegistry { 22 | 23 | private static final Logger LOGGER = LoggerFactory.getLogger(ServiceRegistry.class); 24 | 25 | private CountDownLatch latch = new CountDownLatch(1); 26 | 27 | private String registryAddress; 28 | 29 | public ServiceRegistry(String registryAddress) { 30 | this.registryAddress = registryAddress; 31 | } 32 | 33 | public void register(String data) { 34 | if (data != null) { 35 | ZooKeeper zk = connectServer(); 36 | if (zk != null) { 37 | AddRootNode(zk); // Add root node if not exist 38 | createNode(zk, data); 39 | } 40 | } 41 | } 42 | 43 | private ZooKeeper connectServer() { 44 | ZooKeeper zk = null; 45 | try { 46 | zk = new ZooKeeper(registryAddress, Constant.ZK_SESSION_TIMEOUT, new Watcher() { 47 | @Override 48 | public void process(WatchedEvent event) { 49 | if (event.getState() == Event.KeeperState.SyncConnected) { 50 | latch.countDown(); 51 | } 52 | } 53 | }); 54 | latch.await(); 55 | } catch (IOException e) { 56 | LOGGER.error("", e); 57 | } 58 | catch (InterruptedException ex){ 59 | LOGGER.error("", ex); 60 | } 61 | return zk; 62 | } 63 | 64 | private void AddRootNode(ZooKeeper zk){ 65 | try { 66 | Stat s = zk.exists(Constant.ZK_REGISTRY_PATH, false); 67 | if (s == null) { 68 | zk.create(Constant.ZK_REGISTRY_PATH, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); 69 | } 70 | } catch (KeeperException e) { 71 | LOGGER.error(e.toString()); 72 | } catch (InterruptedException e) { 73 | LOGGER.error(e.toString()); 74 | } 75 | } 76 | 77 | private void createNode(ZooKeeper zk, String data) { 78 | try { 79 | byte[] bytes = data.getBytes(); 80 | String path = zk.create(Constant.ZK_DATA_PATH, bytes, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); 81 | LOGGER.debug("create zookeeper node ({} => {})", path, data); 82 | } catch (KeeperException e) { 83 | LOGGER.error("", e); 84 | } 85 | catch (InterruptedException ex){ 86 | LOGGER.error("", ex); 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/nettyrpc/RPCProxy.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.nettyrpc; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.lang.reflect.Method; 5 | import java.lang.reflect.Proxy; 6 | 7 | import com.tianjunwei.nettyrpc.entity.ClassInfo; 8 | 9 | import io.netty.bootstrap.Bootstrap; 10 | import io.netty.channel.ChannelFuture; 11 | import io.netty.channel.ChannelInitializer; 12 | import io.netty.channel.ChannelOption; 13 | import io.netty.channel.ChannelPipeline; 14 | import io.netty.channel.EventLoopGroup; 15 | import io.netty.channel.nio.NioEventLoopGroup; 16 | import io.netty.channel.socket.SocketChannel; 17 | import io.netty.channel.socket.nio.NioSocketChannel; 18 | import io.netty.handler.codec.LengthFieldBasedFrameDecoder; 19 | import io.netty.handler.codec.LengthFieldPrepender; 20 | import io.netty.handler.codec.serialization.ClassResolvers; 21 | import io.netty.handler.codec.serialization.ObjectDecoder; 22 | import io.netty.handler.codec.serialization.ObjectEncoder; 23 | 24 | 25 | public class RPCProxy { 26 | 27 | @SuppressWarnings("unchecked") 28 | public static T create(Object target){ 29 | 30 | return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), new InvocationHandler(){ 31 | 32 | @Override 33 | public Object invoke(Object proxy, Method method, Object[] args) 34 | throws Throwable { 35 | 36 | ClassInfo classInfo = new ClassInfo(); 37 | classInfo.setClassName(target.getClass().getName()); 38 | classInfo.setMethodName(method.getName()); 39 | classInfo.setObjects(args); 40 | classInfo.setTypes(method.getParameterTypes()); 41 | 42 | ResultHandler resultHandler = new ResultHandler(); 43 | EventLoopGroup group = new NioEventLoopGroup(); 44 | try { 45 | Bootstrap b = new Bootstrap(); 46 | b.group(group) 47 | .channel(NioSocketChannel.class) 48 | .option(ChannelOption.TCP_NODELAY, true) 49 | .handler(new ChannelInitializer() { 50 | @Override 51 | public void initChannel(SocketChannel ch) throws Exception { 52 | ChannelPipeline pipeline = ch.pipeline(); 53 | pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4)); 54 | pipeline.addLast("frameEncoder", new LengthFieldPrepender(4)); 55 | pipeline.addLast("encoder", new ObjectEncoder()); 56 | pipeline.addLast("decoder", new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null))); 57 | pipeline.addLast("handler",resultHandler); 58 | } 59 | }); 60 | 61 | ChannelFuture future = b.connect("localhost", 8080).sync(); 62 | future.channel().writeAndFlush(classInfo).sync(); 63 | future.channel().closeFuture().sync(); 64 | } finally { 65 | group.shutdownGracefully(); 66 | } 67 | return resultHandler.getResponse(); 68 | } 69 | }); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/zknettyRpc/server/RpcHandler.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.zknettyRpc.server; 2 | 3 | import java.util.Map; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import com.tianjunwei.zknettyRpc.protocol.RpcRequest; 9 | import com.tianjunwei.zknettyRpc.protocol.RpcResponse; 10 | 11 | import io.netty.channel.ChannelFuture; 12 | import io.netty.channel.ChannelFutureListener; 13 | import io.netty.channel.ChannelHandlerContext; 14 | import io.netty.channel.SimpleChannelInboundHandler; 15 | import net.sf.cglib.reflect.FastClass; 16 | import net.sf.cglib.reflect.FastMethod; 17 | 18 | /** 19 | * RPC Handler(RPC request processor) 20 | * @author luxiaoxun 21 | */ 22 | public class RpcHandler extends SimpleChannelInboundHandler { 23 | 24 | private static final Logger LOGGER = LoggerFactory.getLogger(RpcHandler.class); 25 | 26 | private final Map handlerMap; 27 | 28 | public RpcHandler(Map handlerMap) { 29 | this.handlerMap = handlerMap; 30 | } 31 | 32 | @Override 33 | public void channelRead0(final ChannelHandlerContext ctx,final RpcRequest request) throws Exception { 34 | RpcServer.submit(new Runnable() { 35 | @Override 36 | public void run() { 37 | LOGGER.debug("Receive request " + request.getRequestId()); 38 | RpcResponse response = new RpcResponse(); 39 | response.setRequestId(request.getRequestId()); 40 | try { 41 | Object result = handle(request); 42 | response.setResult(result); 43 | } catch (Throwable t) { 44 | response.setError(t.toString()); 45 | LOGGER.error("RPC Server handle request error",t); 46 | } 47 | ctx.writeAndFlush(response).addListener(new ChannelFutureListener() { 48 | @Override 49 | public void operationComplete(ChannelFuture channelFuture) throws Exception { 50 | LOGGER.debug("Send response for request " + request.getRequestId()); 51 | } 52 | }); 53 | } 54 | }); 55 | } 56 | 57 | private Object handle(RpcRequest request) throws Throwable { 58 | String className = request.getClassName(); 59 | Object serviceBean = handlerMap.get(className); 60 | 61 | Class serviceClass = serviceBean.getClass(); 62 | String methodName = request.getMethodName(); 63 | Class[] parameterTypes = request.getParameterTypes(); 64 | Object[] parameters = request.getParameters(); 65 | 66 | LOGGER.debug(serviceClass.getName()); 67 | LOGGER.debug(methodName); 68 | for (int i = 0; i < parameterTypes.length; ++i) { 69 | LOGGER.debug(parameterTypes[i].getName()); 70 | } 71 | for (int i = 0; i < parameters.length; ++i) { 72 | LOGGER.debug(parameters[i].toString()); 73 | } 74 | 75 | // JDK reflect 76 | /*Method method = serviceClass.getMethod(methodName, parameterTypes); 77 | method.setAccessible(true); 78 | return method.invoke(serviceBean, parameters);*/ 79 | 80 | // Cglib reflect 81 | FastClass serviceFastClass = FastClass.create(serviceClass); 82 | FastMethod serviceFastMethod = serviceFastClass.getMethod(methodName, parameterTypes); 83 | return serviceFastMethod.invoke(serviceBean, parameters); 84 | } 85 | 86 | @Override 87 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 88 | LOGGER.error("server caught exception", cause); 89 | ctx.close(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/test/java/com/tianjunwei/test/app/HelloServiceTest.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.test.app; 2 | 3 | import static org.hamcrest.MatcherAssert.assertThat; 4 | import static org.hamcrest.core.IsEqual.equalTo; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import java.util.concurrent.ExecutionException; 9 | 10 | import org.junit.Assert; 11 | import org.junit.Test; 12 | import org.junit.runner.RunWith; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.test.context.ContextConfiguration; 15 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 16 | 17 | import com.tianjunwei.test.client.HelloPersonService; 18 | import com.tianjunwei.test.client.HelloService; 19 | import com.tianjunwei.test.client.Person; 20 | import com.tianjunwei.zknettyRpc.client.RPCFuture; 21 | import com.tianjunwei.zknettyRpc.client.RpcClient; 22 | import com.tianjunwei.zknettyRpc.client.proxy.IAsyncObjectProxy; 23 | 24 | @RunWith(SpringJUnit4ClassRunner.class) 25 | @ContextConfiguration(locations = "classpath:client-spring.xml") 26 | public class HelloServiceTest { 27 | 28 | @Autowired 29 | private RpcClient rpcClient; 30 | 31 | @Test 32 | public void helloTest1() { 33 | HelloService helloService = rpcClient.create(HelloService.class); 34 | String result = helloService.hello("World"); 35 | Assert.assertEquals("Hello! World", result); 36 | } 37 | 38 | @Test 39 | public void helloTest2() { 40 | HelloService helloService = rpcClient.create(HelloService.class); 41 | Person person = new Person("Yong", "Huang"); 42 | String result = helloService.hello(person); 43 | Assert.assertEquals("Hello! Yong Huang", result); 44 | } 45 | 46 | @Test 47 | public void helloPersonTest(){ 48 | HelloPersonService helloPersonService = rpcClient.create(HelloPersonService.class); 49 | int num = 5; 50 | List persons = helloPersonService.GetTestPerson("xiaoming",num); 51 | List expectedPersons = new ArrayList<>(); 52 | for (int i = 0; i < num; i++) { 53 | expectedPersons.add(new Person(Integer.toString(i), "xiaoming")); 54 | } 55 | assertThat(persons, equalTo(expectedPersons)); 56 | 57 | for (int i = 0; i persons = (List) result.get(); 83 | List expectedPersons = new ArrayList<>(); 84 | for (int i = 0; i < num; i++) { 85 | expectedPersons.add(new Person(Integer.toString(i), "xiaoming")); 86 | } 87 | assertThat(persons, equalTo(expectedPersons)); 88 | 89 | for (int i = 0; i < num; ++i) { 90 | System.out.println(persons.get(i)); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/zknettyRpc/registry/ServiceDiscovery.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.zknettyRpc.registry; 2 | 3 | import java.io.IOException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.concurrent.CountDownLatch; 7 | import java.util.concurrent.ThreadLocalRandom; 8 | 9 | import org.apache.zookeeper.KeeperException; 10 | import org.apache.zookeeper.WatchedEvent; 11 | import org.apache.zookeeper.Watcher; 12 | import org.apache.zookeeper.ZooKeeper; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | 16 | import com.tianjunwei.zknettyRpc.client.ConnectManage; 17 | 18 | /** 19 | * 服务发现 20 | * 21 | * @author huangyong 22 | * @author luxiaoxun 23 | */ 24 | public class ServiceDiscovery { 25 | 26 | private static final Logger LOGGER = LoggerFactory.getLogger(ServiceDiscovery.class); 27 | 28 | private CountDownLatch latch = new CountDownLatch(1); 29 | 30 | private volatile List dataList = new ArrayList<>(); 31 | 32 | private String registryAddress; 33 | private ZooKeeper zookeeper; 34 | 35 | public ServiceDiscovery(String registryAddress) { 36 | this.registryAddress = registryAddress; 37 | zookeeper = connectServer(); 38 | if (zookeeper != null) { 39 | watchNode(zookeeper); 40 | } 41 | } 42 | 43 | public String discover() { 44 | String data = null; 45 | int size = dataList.size(); 46 | if (size > 0) { 47 | if (size == 1) { 48 | data = dataList.get(0); 49 | LOGGER.debug("using only data: {}", data); 50 | } else { 51 | data = dataList.get(ThreadLocalRandom.current().nextInt(size)); 52 | LOGGER.debug("using random data: {}", data); 53 | } 54 | } 55 | return data; 56 | } 57 | 58 | private ZooKeeper connectServer() { 59 | ZooKeeper zk = null; 60 | try { 61 | zk = new ZooKeeper(registryAddress, Constant.ZK_SESSION_TIMEOUT, new Watcher() { 62 | @Override 63 | public void process(WatchedEvent event) { 64 | if (event.getState() == Event.KeeperState.SyncConnected) { 65 | latch.countDown(); 66 | } 67 | } 68 | }); 69 | latch.await(); 70 | } catch (IOException | InterruptedException e) { 71 | LOGGER.error("", e); 72 | } 73 | return zk; 74 | } 75 | 76 | private void watchNode(final ZooKeeper zk) { 77 | try { 78 | List nodeList = zk.getChildren(Constant.ZK_REGISTRY_PATH, new Watcher() { 79 | @Override 80 | public void process(WatchedEvent event) { 81 | if (event.getType() == Event.EventType.NodeChildrenChanged) { 82 | watchNode(zk); 83 | } 84 | } 85 | }); 86 | List dataList = new ArrayList<>(); 87 | for (String node : nodeList) { 88 | byte[] bytes = zk.getData(Constant.ZK_REGISTRY_PATH + "/" + node, false, null); 89 | dataList.add(new String(bytes)); 90 | } 91 | LOGGER.debug("node data: {}", dataList); 92 | this.dataList = dataList; 93 | 94 | LOGGER.debug("Service discovery triggered updating connected server node."); 95 | UpdateConnectedServer(); 96 | } catch (KeeperException | InterruptedException e) { 97 | LOGGER.error("", e); 98 | } 99 | } 100 | 101 | private void UpdateConnectedServer(){ 102 | ConnectManage.getInstance().updateConnectedServer(this.dataList); 103 | } 104 | 105 | public void stop(){ 106 | if(zookeeper!=null){ 107 | try { 108 | zookeeper.close(); 109 | } catch (InterruptedException e) { 110 | LOGGER.error("", e); 111 | } 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/zknettyRpc/protocol/JsonUtil.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.zknettyRpc.protocol; 2 | 3 | import java.io.IOException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.HashMap; 6 | 7 | import com.fasterxml.jackson.annotation.JsonInclude; 8 | import com.fasterxml.jackson.core.JsonGenerator; 9 | import com.fasterxml.jackson.core.JsonParser; 10 | import com.fasterxml.jackson.core.JsonProcessingException; 11 | import com.fasterxml.jackson.databind.DeserializationFeature; 12 | import com.fasterxml.jackson.databind.JavaType; 13 | import com.fasterxml.jackson.databind.ObjectMapper; 14 | import com.fasterxml.jackson.databind.SerializationFeature; 15 | 16 | /** 17 | * Json Util 18 | * Created by luxiaoxun on 2016-03-09. 19 | */ 20 | public class JsonUtil { 21 | private static ObjectMapper objMapper = new ObjectMapper(); 22 | 23 | static { 24 | SimpleDateFormat dateFormat = new SimpleDateFormat( 25 | "yyyy-MM-dd HH:mm:ss"); 26 | objMapper.setDateFormat(dateFormat); 27 | objMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); 28 | objMapper.enable(SerializationFeature.INDENT_OUTPUT); 29 | objMapper.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false); 30 | objMapper.configure(JsonGenerator.Feature.AUTO_CLOSE_JSON_CONTENT, false); 31 | objMapper.disable(SerializationFeature.FLUSH_AFTER_WRITE_VALUE); 32 | objMapper.disable(SerializationFeature.CLOSE_CLOSEABLE); 33 | objMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); 34 | objMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); 35 | objMapper.configure(JsonParser.Feature.IGNORE_UNDEFINED, true); 36 | } 37 | 38 | public static byte[] serialize(T obj){ 39 | byte[] bytes = new byte[0]; 40 | try { 41 | bytes = objMapper.writeValueAsBytes(obj); 42 | } catch (JsonProcessingException e) { 43 | throw new IllegalStateException(e.getMessage(), e); 44 | } 45 | return bytes; 46 | } 47 | 48 | public static T deserialize(byte[] data, Class cls) { 49 | T obj = null; 50 | try { 51 | obj = objMapper.readValue(data,cls); 52 | } catch (IOException e) { 53 | throw new IllegalStateException(e.getMessage(), e); 54 | } 55 | return obj; 56 | } 57 | 58 | 59 | public static type jsonToObject(String json, Class cls) { 60 | type obj = null; 61 | JavaType javaType = objMapper.getTypeFactory().constructType(cls); 62 | try { 63 | obj = objMapper.readValue(json, javaType); 64 | } catch (IOException e) { 65 | throw new IllegalStateException(e.getMessage(), e); 66 | } 67 | return obj; 68 | } 69 | 70 | public static type jsonToObjectList(String json, 71 | Class collectionClass, Class... elementClass) { 72 | type obj = null; 73 | JavaType javaType = objMapper.getTypeFactory().constructParametricType( 74 | collectionClass, elementClass); 75 | try { 76 | obj = objMapper.readValue(json, javaType); 77 | } catch (IOException e) { 78 | throw new IllegalStateException(e.getMessage(), e); 79 | } 80 | return obj; 81 | } 82 | 83 | public static type jsonToObjectHashMap(String json, 84 | Class keyClass, Class valueClass) { 85 | type obj = null; 86 | JavaType javaType = objMapper.getTypeFactory().constructParametricType(HashMap.class, keyClass,valueClass); 87 | try { 88 | obj = objMapper.readValue(json, javaType); 89 | } catch (IOException e) { 90 | throw new IllegalStateException(e.getMessage(), e); 91 | } 92 | return obj; 93 | } 94 | 95 | public static String objectToJson(Object o) { 96 | String json = ""; 97 | try { 98 | json = objMapper.writeValueAsString(o); 99 | } catch (IOException e) { 100 | throw new IllegalStateException(e.getMessage(), e); 101 | } 102 | return json; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}[%line] - %msg%n 9 | 10 | 11 | 12 | 13 | 14 | 15 | DEBUG 16 | ACCEPT 17 | DENY 18 | 19 | c:\\log\debug.log 20 | 21 | c:\\log\debug.%d{yyyy-MM-dd}.%i.zip 22 | 23 | 1MB 24 | 3 25 | 26 | 27 | 28 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}[%line] - %msg%n 29 | 30 | 31 | 32 | 33 | 34 | ERROR 35 | ACCEPT 36 | DENY 37 | 38 | c:\\log\error.log 39 | 40 | c:\\log\error.%d{yyyy-MM-dd}.%i.zip 41 | 42 | 10MB 43 | 3 44 | 45 | 46 | 47 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}[%line] - %msg%n 48 | 49 | 50 | 51 | 52 | 53 | INFO 54 | ACCEPT 55 | DENY 56 | 57 | c:\\log\info.log 58 | 59 | c:\\log\info.%d{yyyy-MM-dd}.%i.zip 60 | 61 | 10MB 62 | 3 63 | 64 | 65 | 66 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}[%line] - %msg%n 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}[%line] - %msg%n 9 | 10 | 11 | 12 | 13 | 14 | 15 | DEBUG 16 | ACCEPT 17 | DENY 18 | 19 | c:\\log\debug.log 20 | 21 | c:\\log\debug.%d{yyyy-MM-dd}.%i.zip 22 | 23 | 1MB 24 | 3 25 | 26 | 27 | 28 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}[%line] - %msg%n 29 | 30 | 31 | 32 | 33 | 34 | ERROR 35 | ACCEPT 36 | DENY 37 | 38 | c:\\log\error.log 39 | 40 | c:\\log\error.%d{yyyy-MM-dd}.%i.zip 41 | 42 | 10MB 43 | 3 44 | 45 | 46 | 47 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}[%line] - %msg%n 48 | 49 | 50 | 51 | 52 | 53 | INFO 54 | ACCEPT 55 | DENY 56 | 57 | c:\\log\info.log 58 | 59 | c:\\log\info.%d{yyyy-MM-dd}.%i.zip 60 | 61 | 10MB 62 | 3 63 | 64 | 65 | 66 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}[%line] - %msg%n 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/zknettyRpc/server/RpcServer.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.zknettyRpc.server; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.concurrent.ArrayBlockingQueue; 6 | import java.util.concurrent.ThreadPoolExecutor; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | import org.apache.commons.collections4.MapUtils; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | import org.springframework.beans.BeansException; 13 | import org.springframework.beans.factory.InitializingBean; 14 | import org.springframework.context.ApplicationContext; 15 | import org.springframework.context.ApplicationContextAware; 16 | 17 | import com.tianjunwei.zknettyRpc.protocol.RpcDecoder; 18 | import com.tianjunwei.zknettyRpc.protocol.RpcEncoder; 19 | import com.tianjunwei.zknettyRpc.protocol.RpcRequest; 20 | import com.tianjunwei.zknettyRpc.protocol.RpcResponse; 21 | import com.tianjunwei.zknettyRpc.registry.ServiceRegistry; 22 | 23 | import io.netty.bootstrap.ServerBootstrap; 24 | import io.netty.channel.ChannelFuture; 25 | import io.netty.channel.ChannelInitializer; 26 | import io.netty.channel.ChannelOption; 27 | import io.netty.channel.EventLoopGroup; 28 | import io.netty.channel.nio.NioEventLoopGroup; 29 | import io.netty.channel.socket.SocketChannel; 30 | import io.netty.channel.socket.nio.NioServerSocketChannel; 31 | import io.netty.handler.codec.LengthFieldBasedFrameDecoder; 32 | 33 | /** 34 | * RPC Server 35 | * @author huangyong,luxiaoxun 36 | */ 37 | public class RpcServer implements ApplicationContextAware, InitializingBean { 38 | 39 | private static final Logger LOGGER = LoggerFactory.getLogger(RpcServer.class); 40 | 41 | private String serverAddress; 42 | private ServiceRegistry serviceRegistry; 43 | 44 | private Map handlerMap = new HashMap<>(); 45 | 46 | private static ThreadPoolExecutor threadPoolExecutor; 47 | 48 | public RpcServer(String serverAddress) { 49 | this.serverAddress = serverAddress; 50 | } 51 | 52 | public RpcServer(String serverAddress, ServiceRegistry serviceRegistry) { 53 | this.serverAddress = serverAddress; 54 | this.serviceRegistry = serviceRegistry; 55 | } 56 | 57 | @Override 58 | public void setApplicationContext(ApplicationContext ctx) throws BeansException { 59 | Map serviceBeanMap = ctx.getBeansWithAnnotation(RpcService.class); 60 | if (MapUtils.isNotEmpty(serviceBeanMap)) { 61 | for (Object serviceBean : serviceBeanMap.values()) { 62 | String interfaceName = serviceBean.getClass().getAnnotation(RpcService.class).value().getName(); 63 | handlerMap.put(interfaceName, serviceBean); 64 | } 65 | } 66 | } 67 | 68 | @Override 69 | public void afterPropertiesSet() throws Exception { 70 | EventLoopGroup bossGroup = new NioEventLoopGroup(); 71 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 72 | try { 73 | ServerBootstrap bootstrap = new ServerBootstrap(); 74 | bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) 75 | .childHandler(new ChannelInitializer() { 76 | @Override 77 | public void initChannel(SocketChannel channel) throws Exception { 78 | channel.pipeline() 79 | .addLast(new LengthFieldBasedFrameDecoder(65536,0,4,0,0)) 80 | .addLast(new RpcDecoder(RpcRequest.class)) 81 | .addLast(new RpcEncoder(RpcResponse.class)) 82 | .addLast(new RpcHandler(handlerMap)); 83 | } 84 | }) 85 | .option(ChannelOption.SO_BACKLOG, 128) 86 | .childOption(ChannelOption.SO_KEEPALIVE, true); 87 | 88 | String[] array = serverAddress.split(":"); 89 | String host = array[0]; 90 | int port = Integer.parseInt(array[1]); 91 | 92 | ChannelFuture future = bootstrap.bind(host, port).sync(); 93 | LOGGER.debug("Server started on port {}", port); 94 | 95 | if (serviceRegistry != null) { 96 | serviceRegistry.register(serverAddress); 97 | } 98 | 99 | future.channel().closeFuture().sync(); 100 | } finally { 101 | workerGroup.shutdownGracefully(); 102 | bossGroup.shutdownGracefully(); 103 | } 104 | } 105 | 106 | public static void submit(Runnable task){ 107 | if(threadPoolExecutor == null){ 108 | synchronized (RpcServer.class) { 109 | if(threadPoolExecutor == null){ 110 | threadPoolExecutor = new ThreadPoolExecutor(16, 16, 600L, TimeUnit.SECONDS, new ArrayBlockingQueue(65536)); 111 | } 112 | } 113 | } 114 | threadPoolExecutor.submit(task); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/zknettyRpc/client/RPCFuture.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.zknettyRpc.client; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.ExecutionException; 6 | import java.util.concurrent.Future; 7 | import java.util.concurrent.TimeUnit; 8 | import java.util.concurrent.TimeoutException; 9 | import java.util.concurrent.locks.AbstractQueuedSynchronizer; 10 | import java.util.concurrent.locks.ReentrantLock; 11 | 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | import com.tianjunwei.zknettyRpc.protocol.RpcRequest; 16 | import com.tianjunwei.zknettyRpc.protocol.RpcResponse; 17 | 18 | 19 | public class RPCFuture implements Future { 20 | private static final Logger LOGGER = LoggerFactory.getLogger(RPCFuture.class); 21 | 22 | private Sync sync; 23 | private RpcRequest request; 24 | private RpcResponse response; 25 | private long startTime; 26 | 27 | private long responseTimeThreshold = 5000; 28 | 29 | private List pendingCallbacks = new ArrayList(); 30 | private ReentrantLock lock = new ReentrantLock(); 31 | 32 | public RPCFuture(RpcRequest request) { 33 | this.sync = new Sync(); 34 | this.request = request; 35 | this.startTime = System.currentTimeMillis(); 36 | } 37 | 38 | @Override 39 | public boolean isDone() { 40 | return sync.isDone(); 41 | } 42 | 43 | @Override 44 | public Object get() throws InterruptedException, ExecutionException { 45 | sync.acquire(-1); 46 | if (this.response != null) { 47 | return this.response.getResult(); 48 | } else { 49 | return null; 50 | } 51 | } 52 | 53 | @Override 54 | public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { 55 | boolean success = sync.tryAcquireNanos(-1, unit.toNanos(timeout)); 56 | if (success) { 57 | if (this.response != null) { 58 | return this.response.getResult(); 59 | } else { 60 | return null; 61 | } 62 | } else { 63 | throw new RuntimeException("Timeout exception. Request id: " + this.request.getRequestId() 64 | + ". Request class name: " + this.request.getClassName() 65 | + ". Request method: " + this.request.getMethodName()); 66 | } 67 | } 68 | 69 | @Override 70 | public boolean isCancelled() { 71 | throw new UnsupportedOperationException(); 72 | } 73 | 74 | @Override 75 | public boolean cancel(boolean mayInterruptIfRunning) { 76 | throw new UnsupportedOperationException(); 77 | } 78 | 79 | public void done(RpcResponse reponse) { 80 | this.response = reponse; 81 | sync.release(1); 82 | invokeCallbacks(); 83 | // Threshold 84 | long responseTime = System.currentTimeMillis() - startTime; 85 | if (responseTime > this.responseTimeThreshold) { 86 | LOGGER.warn("Service response time is too slow. Request id = " + reponse.getRequestId() + ". Response Time = " + responseTime + "ms"); 87 | } 88 | } 89 | 90 | private void invokeCallbacks() { 91 | lock.lock(); 92 | try { 93 | for (final AsyncRPCCallback callback : pendingCallbacks) { 94 | runCallback(callback); 95 | } 96 | } finally { 97 | lock.unlock(); 98 | } 99 | } 100 | 101 | public RPCFuture addCallback(AsyncRPCCallback callback) { 102 | lock.lock(); 103 | try { 104 | if (isDone()) { 105 | runCallback(callback); 106 | } else { 107 | this.pendingCallbacks.add(callback); 108 | } 109 | } finally { 110 | lock.unlock(); 111 | } 112 | return this; 113 | } 114 | 115 | private void runCallback(final AsyncRPCCallback callback) { 116 | final RpcResponse res = this.response; 117 | RpcClient.submit(new Runnable() { 118 | @Override 119 | public void run() { 120 | if (!res.isError()) { 121 | callback.success(res.getResult()); 122 | } else { 123 | callback.fail(new RuntimeException("Response error", new Throwable(res.getError()))); 124 | } 125 | } 126 | }); 127 | } 128 | 129 | static class Sync extends AbstractQueuedSynchronizer { 130 | 131 | private static final long serialVersionUID = 1L; 132 | 133 | //future status 134 | private final int done = 1; 135 | private final int pending = 0; 136 | 137 | protected boolean tryAcquire(int acquires) { 138 | return getState() == done ? true : false; 139 | } 140 | 141 | protected boolean tryRelease(int releases) { 142 | if (getState() == pending) { 143 | if (compareAndSetState(pending, done)) { 144 | return true; 145 | } 146 | } 147 | return false; 148 | } 149 | 150 | public boolean isDone() { 151 | getState(); 152 | return getState() == done; 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/zknettyRpc/client/proxy/ObjectProxy.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.zknettyRpc.client.proxy; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.lang.reflect.Method; 5 | import java.util.UUID; 6 | 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import com.tianjunwei.zknettyRpc.client.ConnectManage; 11 | import com.tianjunwei.zknettyRpc.client.RPCFuture; 12 | import com.tianjunwei.zknettyRpc.client.RpcClientHandler; 13 | import com.tianjunwei.zknettyRpc.protocol.RpcRequest; 14 | 15 | public class ObjectProxy implements InvocationHandler, IAsyncObjectProxy { 16 | private static final Logger LOGGER = LoggerFactory.getLogger(ObjectProxy.class); 17 | private Class clazz; 18 | 19 | public ObjectProxy(Class clazz) { 20 | this.clazz = clazz; 21 | } 22 | 23 | @Override 24 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 25 | if (Object.class == method.getDeclaringClass()) { 26 | String name = method.getName(); 27 | if ("equals".equals(name)) { 28 | return proxy == args[0]; 29 | } else if ("hashCode".equals(name)) { 30 | return System.identityHashCode(proxy); 31 | } else if ("toString".equals(name)) { 32 | return proxy.getClass().getName() + "@" + 33 | Integer.toHexString(System.identityHashCode(proxy)) + 34 | ", with InvocationHandler " + this; 35 | } else { 36 | throw new IllegalStateException(String.valueOf(method)); 37 | } 38 | } 39 | 40 | RpcRequest request = new RpcRequest(); 41 | request.setRequestId(UUID.randomUUID().toString()); 42 | request.setClassName(method.getDeclaringClass().getName()); 43 | request.setMethodName(method.getName()); 44 | request.setParameterTypes(method.getParameterTypes()); 45 | request.setParameters(args); 46 | // Debug 47 | LOGGER.debug(method.getDeclaringClass().getName()); 48 | LOGGER.debug(method.getName()); 49 | for (int i = 0; i < method.getParameterTypes().length; ++i) { 50 | LOGGER.debug(method.getParameterTypes()[i].getName()); 51 | } 52 | for (int i = 0; i < args.length; ++i) { 53 | LOGGER.debug(args[i].toString()); 54 | } 55 | 56 | RpcClientHandler handler = ConnectManage.getInstance().chooseHandler(); 57 | RPCFuture rpcFuture = handler.sendRequest(request); 58 | return rpcFuture.get(); 59 | } 60 | 61 | @Override 62 | public RPCFuture call(String funcName, Object... args) { 63 | RpcClientHandler handler = ConnectManage.getInstance().chooseHandler(); 64 | RpcRequest request = createRequest(this.clazz.getName(), funcName, args); 65 | RPCFuture rpcFuture = handler.sendRequest(request); 66 | return rpcFuture; 67 | } 68 | 69 | private RpcRequest createRequest(String className, String methodName, Object[] args) { 70 | RpcRequest request = new RpcRequest(); 71 | request.setRequestId(UUID.randomUUID().toString()); 72 | request.setClassName(className); 73 | request.setMethodName(methodName); 74 | request.setParameters(args); 75 | 76 | Class[] parameterTypes = new Class[args.length]; 77 | // Get the right class type 78 | for (int i = 0; i < args.length; i++) { 79 | parameterTypes[i] = getClassType(args[i]); 80 | } 81 | request.setParameterTypes(parameterTypes); 82 | // Method[] methods = clazz.getDeclaredMethods(); 83 | // for (int i = 0; i < methods.length; ++i) { 84 | // // Bug: if there are 2 methods have the same name 85 | // if (methods[i].getName().equals(methodName)) { 86 | // parameterTypes = methods[i].getParameterTypes(); 87 | // request.setParameterTypes(parameterTypes); // get parameter types 88 | // break; 89 | // } 90 | // } 91 | 92 | LOGGER.debug(className); 93 | LOGGER.debug(methodName); 94 | for (int i = 0; i < parameterTypes.length; ++i) { 95 | LOGGER.debug(parameterTypes[i].getName()); 96 | } 97 | for (int i = 0; i < args.length; ++i) { 98 | LOGGER.debug(args[i].toString()); 99 | } 100 | 101 | return request; 102 | } 103 | 104 | private Class getClassType(Object obj){ 105 | Class classType = obj.getClass(); 106 | String typeName = classType.getName(); 107 | switch (typeName){ 108 | case "java.lang.Integer": 109 | return Integer.TYPE; 110 | case "java.lang.Long": 111 | return Long.TYPE; 112 | case "java.lang.Float": 113 | return Float.TYPE; 114 | case "java.lang.Double": 115 | return Double.TYPE; 116 | case "java.lang.Character": 117 | return Character.TYPE; 118 | case "java.lang.Boolean": 119 | return Boolean.TYPE; 120 | case "java.lang.Short": 121 | return Short.TYPE; 122 | case "java.lang.Byte": 123 | return Byte.TYPE; 124 | } 125 | 126 | return classType; 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/com/tianjunwei/zknettyRpc/client/ConnectManage.java: -------------------------------------------------------------------------------- 1 | package com.tianjunwei.zknettyRpc.client; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelFutureListener; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.nio.NioEventLoopGroup; 8 | import io.netty.channel.socket.nio.NioSocketChannel; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import java.net.InetSocketAddress; 13 | import java.net.SocketAddress; 14 | import java.util.HashSet; 15 | import java.util.List; 16 | import java.util.Map; 17 | import java.util.concurrent.*; 18 | import java.util.concurrent.atomic.AtomicInteger; 19 | import java.util.concurrent.locks.Condition; 20 | import java.util.concurrent.locks.ReentrantLock; 21 | 22 | 23 | public class ConnectManage { 24 | 25 | private static final Logger LOGGER = LoggerFactory.getLogger(ConnectManage.class); 26 | private volatile static ConnectManage connectManage; 27 | 28 | EventLoopGroup eventLoopGroup = new NioEventLoopGroup(4); 29 | private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(16, 16, 600L, TimeUnit.SECONDS, new ArrayBlockingQueue(65536)); 30 | 31 | private CopyOnWriteArrayList connectedHandlers = new CopyOnWriteArrayList<>(); 32 | private Map connectedServerNodes = new ConcurrentHashMap<>(); 33 | //private Map connectedServerNodes = new ConcurrentHashMap<>(); 34 | 35 | private ReentrantLock lock = new ReentrantLock(); 36 | private Condition connected = lock.newCondition(); 37 | protected long connectTimeoutMillis = 6000; 38 | private AtomicInteger roundRobin = new AtomicInteger(0); 39 | private volatile boolean isRuning = true; 40 | 41 | private ConnectManage() { 42 | } 43 | 44 | public static ConnectManage getInstance() { 45 | if (connectManage == null) { 46 | synchronized (ConnectManage.class) { 47 | if (connectManage == null) { 48 | connectManage = new ConnectManage(); 49 | } 50 | } 51 | } 52 | return connectManage; 53 | } 54 | 55 | public void updateConnectedServer(List allServerAddress) { 56 | if (allServerAddress != null) { 57 | if (allServerAddress.size() > 0) { // Get available server node 58 | //update local serverNodes cache 59 | HashSet newAllServerNodeSet = new HashSet(); 60 | for (int i = 0; i < allServerAddress.size(); ++i) { 61 | String[] array = allServerAddress.get(i).split(":"); 62 | if (array.length == 2) { // Should check IP and port 63 | String host = array[0]; 64 | int port = Integer.parseInt(array[1]); 65 | final InetSocketAddress remotePeer = new InetSocketAddress(host, port); 66 | newAllServerNodeSet.add(remotePeer); 67 | } 68 | } 69 | 70 | // Add new server node 71 | for (final InetSocketAddress serverNodeAddress : newAllServerNodeSet) { 72 | if (!connectedServerNodes.keySet().contains(serverNodeAddress)) { 73 | connectServerNode(serverNodeAddress); 74 | } 75 | } 76 | 77 | // Close and remove invalid server nodes 78 | for (int i = 0; i < connectedHandlers.size(); ++i) { 79 | RpcClientHandler connectedServerHandler = connectedHandlers.get(i); 80 | SocketAddress remotePeer = connectedServerHandler.getRemotePeer(); 81 | if (!newAllServerNodeSet.contains(remotePeer)) { 82 | LOGGER.info("Remove invalid server node " + remotePeer); 83 | RpcClientHandler handler = connectedServerNodes.get(remotePeer); 84 | handler.close(); 85 | connectedServerNodes.remove(remotePeer); 86 | connectedHandlers.remove(connectedServerHandler); 87 | } 88 | } 89 | 90 | } else { // No available server node ( All server nodes are down ) 91 | LOGGER.error("No available server node. All server nodes are down !!!"); 92 | for (final RpcClientHandler connectedServerHandler : connectedHandlers) { 93 | SocketAddress remotePeer = connectedServerHandler.getRemotePeer(); 94 | RpcClientHandler handler = connectedServerNodes.get(remotePeer); 95 | handler.close(); 96 | connectedServerNodes.remove(connectedServerHandler); 97 | } 98 | connectedHandlers.clear(); 99 | } 100 | } 101 | } 102 | 103 | public void reconnect(final RpcClientHandler handler, final SocketAddress remotePeer){ 104 | if(handler!=null){ 105 | connectedHandlers.remove(handler); 106 | connectedServerNodes.remove(handler.getRemotePeer()); 107 | } 108 | connectServerNode((InetSocketAddress)remotePeer); 109 | } 110 | 111 | private void connectServerNode(final InetSocketAddress remotePeer) { 112 | threadPoolExecutor.submit(new Runnable() { 113 | @Override 114 | public void run() { 115 | Bootstrap b = new Bootstrap(); 116 | b.group(eventLoopGroup) 117 | .channel(NioSocketChannel.class) 118 | .handler(new RpcClientInitializer()); 119 | 120 | ChannelFuture channelFuture = b.connect(remotePeer); 121 | channelFuture.addListener(new ChannelFutureListener() { 122 | @Override 123 | public void operationComplete(final ChannelFuture channelFuture) throws Exception { 124 | if (channelFuture.isSuccess()) { 125 | LOGGER.debug("Successfully connect to remote server. remote peer = " + remotePeer); 126 | RpcClientHandler handler = channelFuture.channel().pipeline().get(RpcClientHandler.class); 127 | addHandler(handler); 128 | } 129 | } 130 | }); 131 | } 132 | }); 133 | } 134 | 135 | private void addHandler(RpcClientHandler handler) { 136 | connectedHandlers.add(handler); 137 | InetSocketAddress remoteAddress = (InetSocketAddress) handler.getChannel().remoteAddress(); 138 | connectedServerNodes.put(remoteAddress, handler); 139 | signalAvailableHandler(); 140 | } 141 | 142 | private void signalAvailableHandler() { 143 | lock.lock(); 144 | try { 145 | connected.signalAll(); 146 | } finally { 147 | lock.unlock(); 148 | } 149 | } 150 | 151 | private boolean waitingForHandler() throws InterruptedException { 152 | lock.lock(); 153 | try { 154 | return connected.await(this.connectTimeoutMillis, TimeUnit.MILLISECONDS); 155 | } finally { 156 | lock.unlock(); 157 | } 158 | } 159 | 160 | public RpcClientHandler chooseHandler() { 161 | CopyOnWriteArrayList handlers = (CopyOnWriteArrayList) this.connectedHandlers.clone(); 162 | int size = handlers.size(); 163 | while (isRuning && size <= 0) { 164 | try { 165 | boolean available = waitingForHandler(); 166 | if (available) { 167 | handlers = (CopyOnWriteArrayList) this.connectedHandlers.clone(); 168 | size = handlers.size(); 169 | } 170 | } catch (InterruptedException e) { 171 | LOGGER.error("Waiting for available node is interrupted! ", e); 172 | throw new RuntimeException("Can't connect any servers!", e); 173 | } 174 | } 175 | int index = (roundRobin.getAndAdd(1) + size) % size; 176 | return handlers.get(index); 177 | } 178 | 179 | public void stop(){ 180 | isRuning = false; 181 | for (int i = 0; i < connectedHandlers.size(); ++i) { 182 | RpcClientHandler connectedServerHandler = connectedHandlers.get(i); 183 | connectedServerHandler.close(); 184 | } 185 | signalAvailableHandler(); 186 | threadPoolExecutor.shutdown(); 187 | eventLoopGroup.shutdownGracefully(); 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.tianjunwei 5 | TTRPC 6 | 1.0.0 7 | jar 8 | TTRPC 9 | 10 | UTF-8 11 | 4.2.4.RELEASE 12 | 2.8.0 13 | 4.12 14 | 15 | 16 | 17 | 18 | 19 | com.dyuproject.protostuff 20 | protostuff-core 21 | 1.0.8 22 | 23 | 24 | com.dyuproject.protostuff 25 | protostuff-runtime 26 | 1.0.8 27 | 28 | 29 | 30 | 31 | org.apache.commons 32 | commons-collections4 33 | 4.0 34 | 35 | 36 | 37 | io.netty 38 | netty-all 39 | 4.1.5.Final 40 | 41 | 42 | 43 | org.apache.zookeeper 44 | zookeeper 45 | 3.5.1-alpha 46 | 47 | 48 | 49 | javax.servlet 50 | javax.servlet-api 51 | 3.1.0 52 | 53 | 54 | 55 | com.caucho 56 | hessian 57 | 4.0.38 58 | 59 | 60 | 61 | com.fasterxml.jackson.core 62 | jackson-databind 63 | 2.7.2 64 | 65 | 66 | 67 | com.fasterxml.jackson.core 68 | jackson-core 69 | 2.7.2 70 | 71 | 72 | 73 | org.apache.xmlrpc 74 | xmlrpc-client 75 | 3.1.3 76 | 77 | 78 | org.apache.xmlrpc 79 | xmlrpc-server 80 | 3.1.3 81 | 82 | 83 | 84 | cglib 85 | cglib 86 | 3.2.4 87 | 88 | 89 | 90 | junit 91 | junit 92 | ${junit.version} 93 | 94 | 95 | 96 | 97 | org.springframework 98 | spring-context 99 | ${spring.version} 100 | 101 | 102 | 103 | 104 | org.springframework 105 | spring-aop 106 | ${spring.version} 107 | 108 | 109 | 110 | 111 | org.springframework 112 | spring-aspects 113 | ${spring.version} 114 | 115 | 116 | 117 | 118 | org.springframework 119 | spring-beans 120 | ${spring.version} 121 | 122 | 123 | 124 | 125 | org.springframework 126 | spring-context-support 127 | ${spring.version} 128 | 129 | 130 | 131 | 132 | org.springframework 133 | spring-core 134 | ${spring.version} 135 | 136 | 137 | 138 | 139 | org.springframework 140 | spring-expression 141 | ${spring.version} 142 | 143 | 144 | 145 | 146 | org.springframework 147 | spring-instrument 148 | ${spring.version} 149 | 150 | 151 | 152 | 153 | 154 | org.springframework 155 | spring-jdbc 156 | ${spring.version} 157 | 158 | 159 | 160 | 161 | org.springframework 162 | spring-jms 163 | ${spring.version} 164 | 165 | 166 | 167 | 168 | org.springframework 169 | spring-messaging 170 | ${spring.version} 171 | 172 | 173 | 174 | 175 | org.springframework 176 | spring-orm 177 | ${spring.version} 178 | 179 | 180 | 181 | org.springframework 182 | spring-oxm 183 | ${spring.version} 184 | 185 | 186 | 187 | org.springframework 188 | spring-test 189 | ${spring.version} 190 | 191 | 192 | 193 | org.springframework 194 | spring-tx 195 | ${spring.version} 196 | 197 | 198 | 199 | org.springframework 200 | spring-web 201 | ${spring.version} 202 | 203 | 204 | 205 | 206 | org.springframework 207 | spring-webmvc 208 | ${spring.version} 209 | 210 | 211 | 212 | 213 | org.springframework 214 | spring-webmvc-portlet 215 | ${spring.version} 216 | 217 | 218 | 219 | 220 | org.springframework 221 | spring-websocket 222 | ${spring.version} 223 | 224 | 225 | org.springframework.data 226 | spring-data-redis 227 | 1.6.2.RELEASE 228 | 229 | 230 | ch.qos.logback 231 | logback-core 232 | 1.1.3 233 | 234 | 235 | ch.qos.logback 236 | logback-classic 237 | 1.1.3 238 | 239 | 240 | org.logback-extensions 241 | logback-ext-spring 242 | 0.1.2 243 | 244 | 245 | 246 | 247 | 248 | src/main/java 249 | 250 | **/*.xml 251 | 252 | 253 | 254 | src/test/java 255 | 256 | **/*.xml 257 | 258 | 259 | 260 | src/main/resources 261 | 262 | **/*.* 263 | 264 | 265 | 266 | 267 | 268 | org.apache.maven.plugins 269 | maven-compiler-plugin 270 | 2.0.2 271 | 272 | 1.8 273 | 1.8 274 | 275 | 276 | 277 | 278 | --------------------------------------------------------------------------------