目的:让本地调用远程方法像是调用本地方法一样简单。
通俗来说就是实现,客户端调用服务器端方法,并且拿到返回结果。
公共接口
public interface PublicMethods {
public String say(String msg);
}
公共接口实现类
public class PublicMethodsImpl implements PublicMethods {
@Override
public String say(String msg) {
return "收到消息:"+msg;
}
}
服务器端
public class NtServer {
public static void main(String[] args) {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap sb = new ServerBootstrap();
sb.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new NtServerHandler());
}
});
ChannelFuture channelFuture = sb.bind(6668).sync();
channelFuture.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}
public class NtServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("读取中……");
if(msg.toString().startsWith("lt")){
String res = new PublicMethodsImpl().say(msg.toString().substring(2, msg.toString().length()));
ctx.writeAndFlush(res);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
客户端
public class NtClient {
private static NtClientHandler handler;
private static ExecutorService executor = Executors.newFixedThreadPool(8);
private static void initClient() {
handler = new NtClientHandler();
NioEventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(handler);
}
});
ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 6668).sync();
}catch (Exception e){
e.printStackTrace();
}
}
Object getBean(final Class<?> serviceClass,final String providerName) {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class<?>[]{serviceClass},
(proxy, method, args) -> {
if(handler==null){
initClient();
}
handler.setMsg(providerName+args[0]);
return executor.submit(handler).get();
});
}
public static void main(String[] args) {
NtClient customer = new NtClient();
PublicMethods service = (PublicMethods) customer.getBean(PublicMethods.class, "lt");
String res = service.say("你好啊,我的世界");
System.out.println("调用的结果 res= " + res);
}
}
public class NtClientHandler extends ChannelInboundHandlerAdapter implements Callable {
private ChannelHandlerContext context;
private String result;
private String msg;
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
context = ctx;
}
@Override
public synchronized void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
result = msg.toString();
System.out.println("执行notify");
notify();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
@Override
public synchronized Object call() throws Exception {
context.writeAndFlush(msg);
System.out.println("执行wait");
wait();
return result;
}
public void setMsg(String msg){
this.msg = msg;
}
}
要点小结
主要是client端用了代理,调用实现了Callable的handler,给服务端发消息。
服务端根据接收的消息去调用方法,返回给客户端。
中间要经过必不可少的编码和解码,思想还不算太难。