[JAVA-周瑜]dubbo-Rpc调用案例代码解析

dubbo3.0-Rpc调用案例代码解析

​ 根据周瑜所讲的Dubbo3.0视频原理解析视频和内容,对源码的内容进行总结分析。视频源为【Dubbo3.0】地表最强!Dubbo快速入门教程,通俗易懂(3小时带你快速玩转)

依赖配置

​ 此处使用版本为dubbo官方推荐的3.2.0-beta.4版本,升级至此版本后需要兼容的springboot框架要求较高,而又因springboot版本升级后最低兼容JDK版本为17,所以需要更新JDK至17版本,并且IDEA版本需要提升至2022.3以上。但我相信聪明的你已经解决了这些问题了!

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.dubbo</groupId>
    <artifactId>dubbo-producter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>dubbo-producter</name>
    <description>dubbo-producter</description>
    <properties>
        <java.version>17</java.version>
        <dubbo.version>3.2.0-beta.4</dubbo.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <!--dubbo相关依赖通过pom引入,包括dubbo-spring-boot-starter-->
            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-bom</artifactId>
                <version>${dubbo.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-dependencies-zookeeper-curator5</artifactId>
                <version>${dubbo.version}</version>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <dependencies>
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-dependencies-zookeeper-curator5</artifactId>
            <type>pom</type>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-reload4j</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</project>

源码

​ 源码分为8个部分:程序入口http服务接收处理器本地接口注册(用于代替bean注入)请求处理器实体类服务注册负载均衡。以这种方式拆分,可以单独替换任何一部分。文末有各部分的调用关系时序图

1.程序入口

UserController

public class UserController {

    public static void main(String[] args) {
        UserService userService = ProxyFactory.getProxy(UserService.class);
        String testdubbo = userService.testdubbo();
    }
}

UserServiceImpl

public class UserServiceImpl implements UserService {

    @Override
    public String testdubbo() {
        return new Random().nextDouble() + "";
    }

    @SneakyThrows
    public static void main(String[] args) {
        LocalRegister.regist(UserService.class.getSimpleName(), UserServiceImpl.class);

        RegisterUrl localhost = new RegisterUrl(InetAddress.getLocalHost().getHostName(), 8081);

        new DubboRegister().add(UserService.class.getSimpleName(),localhost);

        new HttpProvider().start(localhost.getHost(),localhost.getPort());
    }
}

2.http服务

HttpProvider

import com.dubbo.dubboproducter.web.DispatchServlet;
import lombok.SneakyThrows;
import org.apache.catalina.Server;
import org.apache.catalina.Service;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardEngine;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.startup.Tomcat;

public class HttpProvider {

    @SneakyThrows
    public void start(String host, Integer port){
        Tomcat tomcat = new Tomcat();
        Server server = tomcat.getServer();
        Service service = server.findService("Tomcat");

        Connector connector = new Connector();
        connector.setPort(port);

        StandardEngine standardEngine = new StandardEngine();
        standardEngine.setDefaultHost(host);

        StandardHost standardHost = new StandardHost();
        standardHost.setName(host);

        StandardContext standardContext = new StandardContext();
        standardContext.setPath("");
        standardContext.addLifecycleListener(new Tomcat.FixContextListener());

        standardHost.addChild(standardContext);
        standardEngine.addChild(standardHost);
        service.setContainer(standardEngine);
        service.addConnector(connector) ;


        tomcat.addServlet("","DispatchController", new DispatchServlet());
        standardContext.addServletMappingDecoded("/*","DispatchController");
        tomcat.start();
        tomcat.getServer().await();
    }
}

HttpConsumer

import com.dubbo.dubboproducter.utils.DubboObject;
import lombok.SneakyThrows;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

public class HttpConsumer {

    @SneakyThrows
    public Object send(String host, Integer port, DubboObject dubboObject){
        URL http = new URL(URLEncoder.encode("http", StandardCharsets.UTF_8), URLEncoder.encode(host, StandardCharsets.UTF_8), port, "/");
        HttpURLConnection httpURLConnection = (HttpURLConnection) http.openConnection();

        httpURLConnection.setRequestMethod("POST");
        httpURLConnection.setDoOutput(true);

        ObjectOutputStream objectOutputStream = new ObjectOutputStream(httpURLConnection.getOutputStream());
        objectOutputStream.writeObject(dubboObject);
        objectOutputStream.flush();
        objectOutputStream.close();

//        int responseCode = httpURLConnection.getResponseCode();
//        System.out.println("Status Code: "+responseCode);

        return new ObjectInputStream(httpURLConnection.getInputStream()).readObject();

    }
}

3.servlet请求接收处理

DispatchServlet

import com.dubbo.dubboproducter.reaction.DubboHandler;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

public class DispatchServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        new DubboHandler().handler(req,resp);
    }
}

DubboHandler

import com.dubbo.dubboproducter.register.LocalRegister;
import com.dubbo.dubboproducter.utils.DubboObject;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;

public class DubboHandler {

    @SneakyThrows
    public void handler(HttpServletRequest req, HttpServletResponse resp){

        //1.获取方法信息
        DubboObject dubboObject = (DubboObject) new ObjectInputStream(req.getInputStream()).readObject();

        //2.实例化对象并运行方法
        Class clazz = LocalRegister.get(dubboObject.getInterfaceName());

        //a.获取方法
        Method method = clazz.getMethod(dubboObject.getMethodName(), dubboObject.getParamsType());

        //b.实例化对象
        Object obj = clazz.getConstructor().newInstance();

        //c.运行方法
        Object invoke =  method.invoke(obj, dubboObject.getParams());

        new ObjectOutputStream(resp.getOutputStream()).writeObject(invoke);
    }
}

4.LocalRegister接口实现类的实现关系本地注册

import java.util.HashMap;

public class LocalRegister {

    private static final HashMap<String,Class> map = new HashMap<>();

    public static void regist(String className, Class clazz){
        map.put(className,clazz);
    }

    public static void unregist(String className){
        map.remove(className);
    }

    public static Class get(String className){
        return map.get(className);
    }
}

5.proxy发送请求处理

ProxyFactory

import com.dubbo.dubboproducter.loadblance.RandomLoadBlance;
import com.dubbo.dubboproducter.reaction.HttpConsumer;
import com.dubbo.dubboproducter.register.DubboRegister;
import com.dubbo.dubboproducter.register.RegisterUrl;
import com.dubbo.dubboproducter.utils.DubboObject;

import java.lang.reflect.Proxy;
import java.util.Set;

public class ProxyFactory {

    @SuppressWarnings("unchecked")
    public static <T> T getProxy(Class interfaceClass){

        return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(),new Class[]{interfaceClass},(o,m,arg) ->{


            DubboObject dubboObject = new DubboObject(interfaceClass.getSimpleName(), m.getName(),m.getParameterTypes(),arg);

            //获取注册中心的服务信息
            Set<RegisterUrl> registerUrls = new DubboRegister().get(interfaceClass.getSimpleName());

            //进行消费端负载均衡
            RegisterUrl registerUrl = RandomLoadBlance.blacne(registerUrls);

            return new HttpConsumer().send(registerUrl.getHost(), registerUrl.getPort(), dubboObject);
        });
    }

}

6.DubboObject发送请求携带的实例对象

import lombok.AllArgsConstructor;
import lombok.Data;

import java.io.Serializable;

@Data
@AllArgsConstructor
public class DubboObject implements Serializable {

    private String interfaceName;

    private String methodName;

    private Class[] paramsType;

    private Object[] params;

}

7.服务注册

DubboRegister

​ #- 远程服务注册

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.TypeReference;
import lombok.SneakyThrows;
import org.apache.commons.io.IOUtils;

import java.io.*;
import java.util.*;

public class DubboRegister {

    public Map<String, Set<RegisterUrl>> DUBBO_REGISTER = new HashMap<>();

    @SneakyThrows
    public void add(String interfaceName, RegisterUrl registerUrl){
        if (DUBBO_REGISTER.containsKey(interfaceName)){
            Set<RegisterUrl> registerUrls = DUBBO_REGISTER.get(interfaceName);
            registerUrls.add(registerUrl);
        }else {
            DUBBO_REGISTER.put(interfaceName,new HashSet<>(){{this.add(registerUrl);}});
        }

        JSONObject jsonObject = new JSONObject(DUBBO_REGISTER);
        File file = new File("./dubboTestregist.json");
        if (!file.exists()) file.createNewFile();
        FileWriter fileWriter = new FileWriter(file);
        fileWriter.write(jsonObject.toJSONString());
        fileWriter.close();
    }


    public Set<RegisterUrl> get(String interfaceName){
        DUBBO_REGISTER = getJson();

        Set<RegisterUrl> registerUrls = DUBBO_REGISTER.get(interfaceName);


        return registerUrls;
    }

    private Map<String, Set<RegisterUrl>> getJson(){
        try {
            FileReader fileReader = new FileReader("./dubboTestregist.json");
            String jsonString = IOUtils.toString(fileReader);
            return JSONObject.parseObject(jsonString,new TypeReference<Map<String, Set<RegisterUrl>>>(){{}});
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

RegisterUrl

import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.Objects;

@AllArgsConstructor
@Data
public class RegisterUrl {

    private String host;

    private Integer port;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        RegisterUrl that = (RegisterUrl) o;
        return Objects.equals(host, that.host) && Objects.equals(port, that.port);
    }

    @Override
    public int hashCode() {
        return Objects.hash(host, port);
    }
}

8.负载均衡

RandomLoadBlance

import com.dubbo.dubboproducter.register.RegisterUrl;


import java.util.Optional;
import java.util.Set;

public class RandomLoadBlance {


    public static RegisterUrl blacne(Set<RegisterUrl> registerUrls){
        Optional<RegisterUrl> any = registerUrls.stream().findAny();
        assert any.isPresent() : "1231231";
        return any.get();
    }
}

流程时序示意图在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是在Java中本地调用Dubbo代码示例: 1. 引入Dubbo相关依赖 在项目的pom.xml文件中,添加以下依赖: ``` <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.5</version> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.9</version> </dependency> ``` 2. 配置Dubbo 在项目中添加Dubbo的配置文件,例如dubbo.properties,内容如下: ``` # 注册中心地址 dubbo.registry.address=zookeeper://127.0.0.1:2181 # 服务协议 dubbo.protocol.name=dubbo dubbo.protocol.port=20880 ``` 3. 编写Dubbo服务接口 定义Dubbo服务的接口,例如: ``` public interface UserService { User getUserById(long id); } ``` 其中,User是一个自定义的实体类。 4. 实现Dubbo服务接口 实现UserService接口中定义的方法,例如: ``` public class UserServiceImpl implements UserService { public User getUserById(long id) { // 从数据库中获取用户信息 User user = userDao.getUserById(id); return user; } } ``` 其中,userDao是一个自定义的数据访问对象。 5. 本地调用Dubbo服务 (1)使用Dubbo的API 在Java代码中,通过Dubbo的API获取Dubbo服务的代理对象,然后调用代理对象的方法。例如: ``` public class UserServiceTest { public static void main(String[] args) { // 初始化Dubbo ApplicationConfig application = new ApplicationConfig(); application.setName("user-service-consumer"); RegistryConfig registry = new RegistryConfig(); registry.setAddress("zookeeper://127.0.0.1:2181"); registry.setClient("curator"); DubboBootstrap.getInstance() .application(application) .registry(registry) .start(); // 获取Dubbo服务代理对象 ReferenceConfig<UserService> reference = new ReferenceConfig<>(); reference.setInterface(UserService.class); reference.setVersion("1.0.0"); UserService userService = reference.get(); // 调用Dubbo服务方法 User user = userService.getUserById(123); System.out.println(user.toString()); // 关闭Dubbo DubboBootstrap.getInstance().stop(); } } ``` (2)使用Spring的注解 在Java类中使用@Reference注解引入Dubbo服务,然后直接调用注入的服务对象的方法。例如: ``` @Service public class UserServiceConsumer { @Reference(version = "1.0.0") private UserService userService; public User getUserById(long id) { User user = userService.getUserById(id); return user; } } ``` 以上是本地调用Dubbo服务的示例,具体实现方式可以根据项目需求进行调整。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值