#案例:Netty实现
当消费者(customer)和提供者(provider)分别在两台不同的服务器时,通过网络通信socket来实现方法调用的过程称为RPC即Remote Procedure Call (远程过程调用)。
1.整体架构


2.代码实现
Customer
public class ClientBootstrap {
/*定义协议头*/
private final static String PROVIDER_NAME = "###";
public static void main(String[] args) throws InterruptedException {
NettyClient customer = new NettyClient();
customer.startClient();
HelloService helloServiceProxy = (HelloService) customer.getBean(HelloService.class, PROVIDER_NAME);
for (int i = 0; i < 10; i++) {
String res = helloServiceProxy.hello("hello, server" + i);
System.out.println("调用的结果:" + res);
}
}
}
netty
public class NettyClient {
//创建线程池
private static ExecutorService executor = Executors
.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
private static NettyClientHandler clientHandler;
private NioEventLoopGroup group;
private Bootstrap bootstrap;
public NettyClient() {
clientHandler = new NettyClientHandler();
group = new NioEventLoopGroup();
bootstrap = new Bootstrap();
bootstrap.group(group).channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringEncoder())
.addLast(new StringDecoder())
.addLast(clientHandler);
}
});
}
/**
* 使用代理模式,获取一个代理对象
* Thread.currentThread().getContextClassLoader() 获取合适的加载器
*/
public Object getBean(final Class<?> serverClass, final String providerName) {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class<?>[]{serverClass}, (proxy, method, args) -> {
/*设置发送给服务器的信息,providerName是协议头*/
clientHandler.setPara(providerName + args[0]);
/*callable传入线程池某个线程,可再次传给线程池其他线程*/
return executor.submit(clientHandler).get();
});
}
public void startClient() throws InterruptedException {
bootstrap.connect("127.0.0.1", 7000).sync();
System.out.println("connecting the server successfully...");
}
}
public class NettyClientHandler extends ChannelInboundHandlerAdapter implements Callable {
private ChannelHandlerContext context;
private String result;
private String para;
/**
* 1.与服务器连接创建成功后被调用
*
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
//ctx 需要共享
context = ctx;
}
/**
* 2.设置参数
*
* @param para
*/
public void setPara(String para) {
this.para = para;
}
/**
* 3.被代理对象调用,发送数据给服务器 -> wait ->等待被唤醒 ->返回结果
*
* @return
* @throws Exception
*/
@Override
public synchronized Object call() throws Exception {
context.writeAndFlush(para);
//调用当前对象锁
wait();
return result;
}
/**
* 4.读取服务器消息后唤醒call方法
*
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public synchronized void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
result = msg.toString();
/*唤醒等待线程*/
notify();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
public class NettyServer {
private final static int PORT = 7000;
private NioEventLoopGroup boosGroup;
private NioEventLoopGroup workerGroup;
private ServerBootstrap serverBootstrap;
public NettyServer() {
boosGroup = new NioEventLoopGroup(1);
workerGroup = new NioEventLoopGroup();
serverBootstrap = new ServerBootstrap().group(boosGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringDecoder())
.addLast(new StringEncoder())
.addLast(new NettyServerHandler());
}
});
}
private void startServer0() throws InterruptedException {
ChannelFuture future = serverBootstrap.bind(PORT).sync();
System.out.println("provider is beginning to serving...");
future.channel().closeFuture().sync();
}
/**
* 方法重载
*
* @throws InterruptedException
*/
public void startServer() throws InterruptedException {
startServer0();
}
}
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
HelloService helloService = new HelloServerImpl();
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("msg:" + msg.toString());
/*自定义协议,客户端每次发送消息需要以某段字符串开头*/
if (msg.toString().startsWith("###")) {
String result = helloService.hello(msg.toString()
.substring(msg.toString().lastIndexOf("#") + 1));
ctx.writeAndFlush(result);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
provider
public class HelloServerImpl implements HelloService {
@Override
public String hello(String msg) {
System.out.println("收到消费者消息" + msg);
if (msg != null) {
return "hello customer, I have received your message [" + msg + "]";
} else {
return "hello customer, I have received your message";
}
}
}
/**
* 启动一个NettyServer
*/
public class ServerBootstrap {
public static void main(String[] args) throws InterruptedException {
new NettyServer().startServer();
}
}
interface
/**
* 公共接口
*/
public interface HelloService {
String hello(String msg);
}


浙公网安备 33010602011771号