Netty实现DubboRPC实例
程序目录结构
实现思路
1.client创建一个HelloService的动态代理
2.动态代理对象实现向nettyService发送消息,并得到nettyService的返回值
3.nettyService实现针对client发送的数据解析,并调用HelloServiceImpl,并把值回写到client
服务接口HelloService
package com.netty.dubbo;
public interface HelloService {
String hello(String str);
}
服务实现类HelloServiceImpl
package com.netty.dubbo;
public class HelloServiceImpl implements HelloService {
@Override
public String hello(String str) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(str != null){
return str + " 111";
}
return null;
}
}
Netty服务端NettyServer
1.创建一个netty服务端
2.新增StringDecoder解析器
3.新增 StringEncoder解析器
4.新增自定义NettyServerHandler
package com.netty.dubbo.netty;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class NettyServer {
public static void startServer(String hostName, int port){
startServer0(hostName,port);
}
private static void startServer0(String hostName, int port){
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workGroup = new NioEventLoopGroup();
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup,workGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new NettyServerHandler());
}
});
try{
ChannelFuture channelFuture = serverBootstrap.bind(hostName, port).sync();
System.out.println("服务提供方启动....");
channelFuture.channel().closeFuture().sync();
}catch (Exception e ){
e.printStackTrace();
}finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
}
自定义NettyServerHandler
在channelRead针对特定的msg解析,这儿针对HelloService#hello#前缀的,调用helloService请求,并通过ctx.writeAndFlush返回到client端
package com.netty.dubbo.netty;
import com.netty.dubbo.ClientBootstrap;
import com.netty.dubbo.HelloServiceImpl;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("client msg:" + msg);
if(msg.toString().startsWith(ClientBootstrap.prividerName)){
String hello = new HelloServiceImpl().hello(msg.toString().substring(msg.toString().lastIndexOf("#") + 1));
ctx.writeAndFlush(hello);
System.out.println("server send message:"+hello);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
Netty客户端NettyClient
1.创建nettyClient
2.创建一个服务代理getBeans,这儿通过线程池调用ExecutorService获取
package com.netty.dubbo.netty;
import com.netty.dubbo.HelloService;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class NettyClient {
private static NettyClientHandler client;
private static ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
public Object getBeans(final Class<?> serviceClass, final String providerName){
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[]{serviceClass}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(client == null){
initClient();
}
client.setPara(providerName +args[0]);
return executorService.submit(client).get();
}
});
}
private static void initClient(){
client = new NettyClientHandler();
NioEventLoopGroup workGroup = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(workGroup)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY,true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(client);
}
});
try{
ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 6666).sync();
System.out.println("客户端启动....");
//channelFuture.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
// workGroup.shutdownGracefully();
}
}
}
自定义NettyClientHandler
1.实现Callable接口,在动态代理中调用call方法
2.调用call方法,首先往server端发送数据,然后wait(),待channelRead读取数据后,再返回
package com.netty.dubbo.netty;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.concurrent.Callable;
public class NettyClientHandler extends ChannelInboundHandlerAdapter implements Callable{
private ChannelHandlerContext context; //上下文
private String result;
private String para; //参数
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
this.context = ctx;
//context.writeAndFlush("aaaa");
}
@Override
public synchronized void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("channelRead method invoke");
result = msg.toString();
System.out.println("server message:"+result);
notify();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
public void setPara(String para) {
this.para = para;
}
@Override
public synchronized Object call() throws Exception {
System.out.println("call method invoke");
context.writeAndFlush(para); //发送消息给服务端
System.out.println("send message :"+ para);
wait(); //等待 channelRead 获取到数据
return result;
}
}
服务端ServerBootstrap
package com.netty.dubbo;
import com.netty.dubbo.netty.NettyServer;
public class ServerBootstrap {
public static void main(String[] args) {
NettyServer.startServer("127.0.0.1",6666);
}
}
客户端ClientBootstrap
package com.netty.dubbo;
import com.netty.dubbo.netty.NettyClient;
public class ClientBootstrap {
public static final String prividerName = "HelloService#hello#";
public static void main(String[] args) {
NettyClient customer = new NettyClient();
HelloService helloService = (HelloService)customer.getBeans(HelloService.class, prividerName);
String str = helloService.hello("ni hao ");
System.out.println("服务端返回结果:"+str);
}
}