上一遍介绍了设计传输模时接口的定义(http://blog.csdn.net/csujiangyu/article/details/51761479)
这里用了主流的框架netty来实现。
首先设计NettyServer,主要功能是绑定端口,监听连接。
public class NettyServer extends AbstractServer { private ServerBootstrap serverBootstrap; private EventLoopGroup bossGroup; private EventLoopGroup workerGroup; public NettyServer(ChannelHandler handler) { super(handler); } @Override public void bind(InetSocketAddress address) throws InterruptedException { bossGroup = new NioEventLoopGroup(); workerGroup = new NioEventLoopGroup(); serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { // (4) @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new DecoderHandler()); ch.pipeline().addLast(new NettyServerHandler(channelHandler)); ch.pipeline().addLast(new EncoderHandler()); } }) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); serverBootstrap.bind(address).sync(); } @Override public void close() { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } @Override public boolean isClosed() { return false; } }
这里为了简单,有些方法没有实现,比如isClosed,只是返回false。
NettyClient实现如下,主要是向服务端发起请求,建立连接。
public class NettyClient implements Client{ private Bootstrap bootstrap; private NioEventLoopGroup workerGroup; private ChannelHandler channelHandler; public NettyClient(ChannelHandler channelHandler){ this.channelHandler = channelHandler; init(); } private void init(){ workerGroup = new NioEventLoopGroup(); bootstrap = new Bootstrap(); bootstrap.group(workerGroup); // (2) bootstrap.channel(NioSocketChannel.class); // (3) bootstrap.option(ChannelOption.SO_KEEPALIVE, true); // (4) bootstrap.handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new DecoderHandler()); ch.pipeline().addLast(new NettyClientHandler(channelHandler)); ch.pipeline().addLast(new EncoderHandler()); } }); } @Override public Channel connect(InetSocketAddress inetSocketAddress) throws Exception { ChannelFuture f = bootstrap.connect(inetSocketAddress).sync(); io.netty.channel.Channel channel = f.channel(); return new NettyChannel(channel, channelHandler); } }
还需要实现Channel的实现
public class NettyChannel implements Channel {
private static final ConcurrentHashMap<io.netty.channel.Channel, NettyChannel> channelMap = new ConcurrentHashMap<>();
//包装netty的client,用到了适配器模式
private io.netty.channel.Channel channel;
private ChannelHandler channelHandler;
public NettyChannel(io.netty.channel.Channel channel, ChannelHandler channelHandler) {
this.channel = channel;
this.channelHandler = channelHandler;
}
static NettyChannel getOrAddChannel(io.netty.channel.Channel channel, ChannelHandler handler) {
NettyChannel ret = channelMap.get(channel);
//不存在则尝试更新
if (ret == null) {
NettyChannel nettyChannel = new NettyChannel(channel, handler);
//这里处于线程安全考虑,如果存在则更新,直接返回
ret = channelMap.putIfAbsent(channel, nettyChannel);
if (ret == null) {
ret = nettyChannel;
}
}
return ret;
}
static void removeIfInactive(io.netty.channel.Channel channel) {
if (channel != null && !channel.isActive()) {
channelMap.remove(channel);
}
}
@Override
public void send(Object message) {
this.channel.writeAndFlush(message);
}
@Override
public ChannelHandler getChannelHandler() {
return channelHandler;
}
@Override
public void close() {
}
@Override
public boolean isClosed() {
return false;
}
@Override
public InetSocketAddress getRemoteAddress() {
return null;
}
@Override
public boolean isConnnect() {
return false;
}
}
然后是NettyServerHandler的实现
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
//消息转发到自定义可扩展的ChannelHandler
private ChannelHandler channelHandler;
public NettyServerHandler(ChannelHandler channelHandler){
this.channelHandler = channelHandler;
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
NettyChannel.getOrAddChannel(ctx.channel(), channelHandler);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object object) throws Exception {
NettyChannel nettyChannel = NettyChannel.getOrAddChannel(ctx.channel(), channelHandler);
channelHandler.receive(nettyChannel, object);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
NettyChannel.removeIfInactive(ctx.channel());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
NettyClientHandler:
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
private ChannelHandler channelHandler;
public NettyClientHandler(ChannelHandler channelHandler) {
this.channelHandler = channelHandler;
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
NettyChannel.getOrAddChannel(ctx.channel(), channelHandler);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object object) throws Exception {
NettyChannel nettyChannel = NettyChannel.getOrAddChannel(ctx.channel(), channelHandler);
channelHandler.receive(nettyChannel, object);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
下面我们来验证一下,看能否满足SOA传输的需要。
定义服务提供者,用于暴露服务,这里的服务是HelloService
public class RpcProvider {
private static final Map<String, Invoker> invokers = new ConcurrentHashMap<>();
public static Invoker getInvoker(String className) {
return invokers.get(className);
}
public static void export(String interfaceName, Class<?> clazz) {
Invoker invoker = new ServerInvoker(clazz);
invokers.put(interfaceName, invoker);
}
private static final ChannelHandler requestHandler = new AbstractChannelHandler() {
@Override
public void receive(Channel channel, Object object) throws Exception {
if (object instanceof Request) {
Request request = (Request) object;
Invocation invocation = request.getInvocation();
Invoker invoker = getInvoker(invocation.getClazz().getSimpleName());
Result result = invoker.invoke(invocation);
Response response = new Response();
response.setMsgId(request.getMsgId());
response.setResult(result.getData());
send(channel, response);
}
}
};
public static void main(String[] args) throws Exception {
Server server = new NettyServer(requestHandler);
server.bind(new InetSocketAddress(Constant.LOCAL_HOST, Constant.PORT));
export(HelloService.class.getSimpleName(), HelloServiceImpl.class);
}
}
然后是定义消费者,发起RPC请求,引用远程服务HelloService
public class RpcConsumer {
private static final ChannelHandler requestHandler = new AbstractChannelHandler() {
@Override
public void receive(Channel channel, Object message) throws Exception {
if (message instanceof Response) {
Response response = (Response) message;
ResponseFuture future = ResponseFuture.getFuture(response.getMsgId());
future.receive(response);
}
}
};
private static final Client client = new NettyClient(requestHandler);
public static <T> T refer(final Class<T> clazz) throws Exception {
final Channel channel = client.connect(new InetSocketAddress(Constant.LOCAL_HOST, Constant.PORT));
ExchangeClient exchangeClient = new ExchangeClient();
final ClientInvoker clientInvoker = new ClientInvoker(clazz);
clientInvoker.setExchangeClient(exchangeClient);
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{clazz}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Invocation invocation = new Invocation();
invocation.setClazz(clazz);
invocation.setMethodName(method.getName());
invocation.setParameterTypes(method.getParameterTypes());
invocation.setArguments(args);
Request request = new Request();
request.setInvocation(invocation);
ResponseFuture responseFuture = new ResponseFuture(request.getMsgId());
channel.send(request);
Response response = responseFuture.get();
return response.getResult();
}
});
}
public static void main(String[] args) throws Exception {
HelloService helloService = refer(HelloService.class);
for (int i = 0; i < 100; i++) {
String string = helloService.hello("Foo");
System.out.println(string);
Thread.sleep(1000);
}
}
}
分别启动上面两个程序,RpcConsumer控制台不断打印“Hello Foo”,说明调用成功。
Hello Foo
Hello Foo
Hello Foo
Hello Foo
源代码在https://github.com/Jdoing/example/tree/master/example-transport/src/main/java/example/transport/netty
和https://github.com/Jdoing/example/tree/master/example-soa/src/main/java/rpc3