netty实现RPC远程调用服务(简要说明)

RPC著名框架为Dubbo
其中生产者和消费者都需要创建一个接口服务类,通过这个类进行服务调用

生产者有接口实现类

消费者有接口所需的参数

服务中心需要对服务进行管理,和参数的返回

核心难点:利用接口类的构造器进行反射(说法可能不太对)
看下面

public static void main(String[] args) throws InterruptedException {

        RPClientPro rpClientPro=new RPClientCus().RPContextApplication();
        //重点:接口获取实例
        Test1 mc= RpcClientProxy.getProxy(Test1.class,rpClientPro);
        //调用方法触发invoke,
        System.out.println(mc.SayNumber());
    }
 public  static <T> T getProxy(Class<T> clazz,RPClientPro rpClientPro) {
        return (T) Proxy.newProxyInstance(clazz.getClassLoader()
                , new Class<?>[]{clazz},
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("开启事务");
//这里可以获取到参数,Customer在这里进行RPC方法参数传输
                        System.out.println("关闭事务");
                        return obj;
                    }
                });
    }

RPC中netty数据流程图
这里通讯工具使用netty,使用类序列化和反序列化进行传输即可。
注意Channel和Ctx不可序列化,类包含这个将无法序列化传输。

  1. 需要开启服务注册中心
  2. 生产者进行服务传输并且连接
  3. 消费者进行服务请求
  4. 服务中心进行服务调用,并且返回

加粗样式

如果想象Dubbo一样使用配置文件
就需要这个进行文件读取
在这里插入图片描述

    public Beans(String configxml) throws Exception {
        SAXReader reader = new SAXReader();
        URL sources = Beans.class.getClassLoader().getResource(configxml);
        Document document = reader.read(sources);
        List<Element> elements = document.getRootElement().elements();
        for (Element element : elements) {
            String id = element.attributeValue("id");//获取id属性
            String path = element.attributeValue("path");//获取class属性
            String clazz = element.attributeValue("class");//获取class属性
            try {
                beansList.add(Class.forName(path));
                beansPath.put(id,path);
                beansObject.put(id,Class.forName(clazz).newInstance());
            }catch (Exception e){
            }
        }

    }
<?xml version="1.0" encoding="UTF-8" ?>
<!--自定义 父节点-->
<beans>
    <!--自定义 子节点-->
    <beans id="cat" path="com.PRC.Service.Test1" />
    <beans id="dog" path="com.PRC.Service.Test"/>
</beans>

或者你想要使用注解直接修饰interface

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ProvideMethod {

}
@ProvideMethod
public interface Test1 {
    int SayNumber();
    String SayString (String param);
}

这个获取注解标识的interface

 Reflections reflections = new Reflections();
        Set<Class> classes = reflections.getTypesAnnotatedWith(ProvideMethod.class);

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.conpany.RPC</groupId>
    <artifactId>RPC</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.50.Final</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.36</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.30</version>
        </dependency>
        <dependency>
            <groupId>org.reflections</groupId>
            <artifactId>reflections</artifactId>
            <version>0.9.10</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.18</version>
        </dependency>
        <!-- dom4j 依赖-->
        <dependency>
            <groupId>org.dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>2.1.1</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
               <artifactId>junit</artifactId>
            <version>4.11</version>
               <scope>test</scope>
        </dependency>
    </dependencies>
</project>

github链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Netty模拟RPC调用需要先了解RPC的基本概念和原理,以及Netty框架的使用方法。 RPC(Remote Procedure Call)远程过程调用是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用显式地编写远程调用的代码。RPC通常基于客户端/服务器模型,客户端向服务器发送RPC请求,服务器响应请求并返回结果。 Netty是一个高性能的、异步的、事件驱动的网络编程框架,它可以轻松地实现RPC调用。 下面是一个简单的Java代码示例,演示如何使用Netty模拟RPC调用: 1. 首先需要定义一个接口,这个接口定义了要远程调用的方法: ```java public interface HelloService { String sayHello(String name); } ``` 2. 接下来创建一个实现类,实现HelloService接口: ```java public class HelloServiceImpl implements HelloService { @Override public String sayHello(String name) { return "Hello, " + name + "!"; } } ``` 3. 创建一个服务端程序,启动Netty服务端,并将HelloServiceImpl注册到服务端: ```java public class Server { public static void main(String[] args) throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null))); pipeline.addLast(new ObjectEncoder()); pipeline.addLast(new ServerHandler()); } }); ChannelFuture f = b.bind(8888).sync(); f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } private static class ServerHandler extends SimpleChannelInboundHandler<Object> { @Override protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof RpcRequest) { RpcRequest request = (RpcRequest) msg; String className = request.getClassName(); String methodName = request.getMethodName(); Class<?>[] parameterTypes = request.getParameterTypes(); Object[] parameters = request.getParameters(); // 根据类名获取实现类 Class<?> clazz = Class.forName(className); Object service = clazz.newInstance(); // 根据方法名和参数类型获取方法 Method method = clazz.getMethod(methodName, parameterTypes); // 执行方法 Object result = method.invoke(service, parameters); // 返回结果 ctx.writeAndFlush(result); } } } } ``` 4. 创建一个客户端程序,通过Netty客户端向服务端发送RPC请求: ```java public class Client { public static void main(String[] args) throws Exception { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new ObjectEncoder()); pipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null))); pipeline.addLast(new ClientHandler()); } }); ChannelFuture f = b.connect("localhost", 8888).sync(); // 发送RPC请求 RpcRequest request = new RpcRequest(); request.setClassName("com.example.HelloServiceImpl"); request.setMethodName("sayHello"); request.setParameterTypes(new Class<?>[] { String.class }); request.setParameters(new Object[] { "world" }); f.channel().writeAndFlush(request); // 等待响应 f.channel().closeFuture().sync(); } finally { group.shutdownGracefully(); } } private static class ClientHandler extends SimpleChannelInboundHandler<Object> { @Override protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { // 处理响应结果 System.out.println(msg); ctx.channel().close(); } } } ``` 这样,我们就通过Netty模拟了一次RPC调用。当客户端向服务端发送RPC请求时,服务端会根据请求参数调用相应的方法并返回结果,客户端收到响应结果后输出到控制台。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值