ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup,workGroup);
bootstrap.channel(NioServerSocketChannel.class);
bootstrap.childHandler(new ChannelInitializer() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(“decoder”,new StringDecoder());
pipeline.addLast(“encoder”,new StringEncoder());
pipeline.addLast(new ServerHandler());
}
});
try {
ChannelFuture sync = bootstrap.bind(address, port).sync();
sync.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
}
第三步:编写Provider启动入口
//启动提供者
public class ProviderStart {
public static void main(String[] args) {
new NettyServer().start(“127.0.0.1”,1000);
}
}
第四步:编写ServerHandler,在channelRead0读取到数据,需要解析内容,匹配相关的service接口,且调用方法,把结果写回给客户端
public class ServerHandler extends SimpleChannelInboundHandler {
//这里没有Spring的容器,就搞一个Map
ConcurrentHashMap<String, Object> applicationContext = new ConcurrentHashMap<>();
public ServerHandler(){
applicationContext.put(“cn.itsource.rpc.api.UserApi”,new UserApiImpl());
}
//消息内容约定 cn.itsource.rpc.api.UserApi#save#数据
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("服务端收到请求 -> "+msg);
String[] msgs = msg.split(“#”);
String interfaceClass = msgs[0];
String methodName = msgs[1];
String data = msgs[2];
//调研Bean的方法
Object obj = applicationContext.get(interfaceClass);
Class<?> aClass = obj.getClass();
Method method =aClass.getMethod(methodName,data.getClass());
//调用方法
Object result = method.invoke(obj,data);
if(result instanceof String){
ctx.writeAndFlush((String)result);
}else{
System.out.println(“类型不支持”);
}
}
}
上面只是简单模拟了一下servie调用,整合Sping可以根据类型去容器中获取Bean。到这服务端编写完成
消费者
消费者要复杂一些,第一步:先编写NettyClient
public class NettyClient {
//客户端处理器,是一个 Callable
private ClientHandler clientHandler = null;
//初始化netty客户端
public void init(String address, int port){
NioEventLoopGroup workGroup = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(workGroup);
bootstrap.channel(NioSocketChannel.class);
clientHandler = new ClientHandler();
bootstrap.handler(new ChannelInitializer() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
//一个客户端一个handler
pipeline.addLast(clientHandler);
}
});
try {
ChannelFuture sync = bootstrap.connect(address, port).sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//执行任务的线程池
ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
public Object getBean(Class userApiClass) {
//创建 userApi 接口的代理
Object proxyInstance = Proxy.newProxyInstance(userApiClass.getClassLoader(), new Class[]{userApiClass}, (proxy, method, args) -> {
//初始化客户端,连接Netty服务端
if(clientHandler == null)init(“127.0.0.1”,1000);
//把协议头#数据 ,传递给handler
clientHandler.setContent(userApiClass.getName()+“#”+method.getName()+“#”+args[0]);
//把请求交给线程池处理,clientHandler就是一个线程
return executorService.submit(clientHandler).get();
});
return proxyInstance;
}
}
NettyClient中提供了两个方法,init和 getBean方法。在init方法中去初始化NettyClient ,ClientHandler提升为了成员变量,因为下getBean面生成代理的时候会用到,然后getBean方法为接口生成了代理。在代理中把需要发送的内容“类权限定名#方法名#数据”交给Handler,把clientHandler交给线程池去执行。