<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          手寫一個rpc遠程調用服務demo

          共 9828字,需瀏覽 20分鐘

           ·

          2021-04-14 17:19

          點擊上方藍色字體,選擇“標星公眾號”

          優(yōu)質文章,第一時間送達

          76套java從入門到精通實戰(zhàn)課程分享

          前言

          • 因為公司業(yè)務需求,使用了K8S + istio進行服務部署和治理,沒有使用常規(guī)的springclould技術棧(包括注冊中心nacos和openfeign遠程服務調用)。

          • 所以就自己開發(fā)了一個基于AOP實現的rpc遠程調用服務模塊。其實現原理實現和feign類似,都是通過遠程調用方法的代理對象發(fā)送HTTP請求并返回結果。

          • 廢話不多說,下面直接上代碼

          代碼

          • 下圖是demo模塊劃分,common是公共模塊,demo-order和demo-user是模擬兩個服務調用。

          • 定義一個標識為遠程調用類的注解 @RpcService ,有點類似于feign的@FeignClient注解。

          /**
           *
           * @AUTHOR ZRH
           * @DATE 2021/4/10
           */
          @Component
          @Retention(RetentionPolicy.RUNTIME)
          @Target(ElementType.TYPE)
          public @interface RpcService {

              /**
               * 遠程服務名稱
               */
              String service();

              /**
               * 端口
               */
              String port();
          }


          • 定義兩個標識遠程調用接口請求方式注解 @get和@post,相當于@PostMapping和@GetMapping。

          /**
           *
           * @AUTHOR ZRH
           * @DATE 2021/4/10
           */
          @Retention(RetentionPolicy.RUNTIME)
          @Target(ElementType.METHOD)
          public @interface Post {

              /**
               * 接口路由
               *
               * @return
               */
              String value();
          }

          /**
           *
           * @AUTHOR ZRH
           * @DATE 2021/4/10
           */
          @Retention(RetentionPolicy.RUNTIME)
          @Target(ElementType.METHOD)
          public @interface Get {

              /**
               * 接口路由
               *
               * @return
               */
              String value();
          }

          • 然后定義一個AOP切面處理類 AopRpcHandler。只要遠程調用接口方法上有注解@Post或者@Get,就會對方法進行代理方式請求。因為這里不需要原本遠程調用方法的執(zhí)行結果,所以這里直接使用@Around環(huán)繞切面,并且不需要執(zhí)行原方法,所以直接使用JoinPoint 做參數接口(ProceedingJoinPoint繼承自JoinPoint,里面多了兩個阻塞方法proceed,用于獲取原代理方法的執(zhí)行結果)。

          • 通過代理對象獲取到原方法的參數值,參數名,接口路由地址,接口請求方式,遠程服務和端口等等。使用okhttp工具類發(fā)送代理請求,然后返回響應結果。

          /**
           * @AUTHOR ZRH
           * @DATE 2021/4/10
           */
          @Slf4j
          @Aspect
          @Component
          public class AopRpcHandler {

              private final static String HTTP = "http://";

              @Around(value = "@annotation(post)")
              public String aopPost(JoinPoint joinPoint, Post post) {
                  String result = null;
                  String url = null;
                  try {
                      RpcService rpcService = (RpcService) joinPoint.getSignature().getDeclaringType().getAnnotation(RpcService.class);
                      url = HTTP + rpcService.service() + ":" + rpcService.port() + "/" + post.value();
                      Object[] args = joinPoint.getArgs();
                      result = OkHttpUtils.post(url, JSON.toJSONString(args[0]));
                  } catch (Throwable throwable) {
                      log.error("服務調用異常,url = [{}]", url);
                  }
                  return result;
              }

              @Around(value = "@annotation(get)")
              public String aopGet(JoinPoint joinPoint, Get get) {
                  String result = null;
                  String url = null;
                  try {
                      RpcService rpcService = (RpcService) joinPoint.getSignature().getDeclaringType().getAnnotation(RpcService.class);
                      url = HTTP + rpcService.service() + ":" + rpcService.port() + "/" + get.value();

                      MethodSignature signature = (MethodSignature) joinPoint.getSignature();
                      Parameter[] parameters = signature.getMethod().getParameters();
                      if (parameters != null && parameters.length > 0) {
                          Object[] args = joinPoint.getArgs();
                          int length = parameters.length;
                          url += "?";
                          for (int i = 0; i < length; i++) {
                              url += parameters[i] + "=" + args[i];
                              if (i != length - 1) {
                                  url += "&";
                              }
                          }
                      }
                      result = OkHttpUtils.get(url);
                  } catch (Throwable throwable) {
                      log.error("服務調用異常,url = [{}]", url);
                  }
                  return result;
              }
          }

          • 然后在demo-user服務中如果有遠程調用場景,就創(chuàng)建一個遠程調用類。使用注解@RpcService和@Post即可。方法中的返回值和返回類型可以自定義,比如一般項目中會有統(tǒng)一的響應結果。

          /**
           * @AUTHOR ZRH
           * @DATE 2021/4/10 0010 1:06
           */
          @RpcService(service = "demo-order", port = "18002")
          public class AopRpcDemo {

              @Post("post")
              public String post(String param) {
                  return "1";
              }
          }

          • 在demo-user服務中使用和正常調用接口一樣。

          /**
           * @AUTHOR ZRH
           * @DATE 2021/4/10 0010 0:42
           */
          @RestController
          public class DemoController {

              @Autowired
              private AopRpcDemo aopRpcDemo;

              @PostMapping("post")
              public String post() {
                  String post = aopRpcDemo.post("zrh.post");
                  System.out.println("調用遠程接口方法返回結= " + post);
                  return "ok";
              }
          }

          • 如果就這樣把demo服務啟動后,訪問是訪問不了的。因為在aop切面處理類中對http請求的URL沒有通過域名而是通過服務名稱拼接的。

          • 這里如果是基于注冊中心和feign進行服務調用,那是沒有問題,因為feign會通過服務名稱到注冊中心找到對應服務的地址進行請求遠程接口。

          • 而這里因為沒有使用注冊中心,所以在window上需要增加hosts文件上的地址映射關系。在C:\Windows\System32\drivers\etc目錄下的hosts文件增加。并在cmd控制臺中使用ipconfig /flushdns刷新DNS內容。

          • @RpcService中的service寫服務名而不寫服務訪問域名,是因為如果是多機集群部署,那么就可以使用服務名映射域名方式通過Nginx負載均衡進行轉發(fā)請求。如果直接寫服務訪問域名就只能訪問一個機子上的服務了。

          • 先看一下兩個服務的配置文件和demo-order的接口



          • 服務啟動后,訪問http://localhost:18001/post,結果如下圖:



          • 最后的結果和我們想要的結果一致。

          • 上面的demo是很簡單的實現。如果讀者想要在自己項目中使用此類技術棧,那需要考慮服務容錯,服務發(fā)現,服務限流等等是否能兼容等。

          最后

          • openfeign其實是可以獨立和springboot進行使用的。先引入openfeign的maven包

                  <dependency>
                      <groupId>org.springframework.cloud</groupId>
                      <artifactId>spring-cloud-starter-openfeign</artifactId>
                      <version>3.0.2</version>
                  </dependency>
           
          • 然后在使用@FeignClient注解時,對url配置接口的訪問地址,最后的執(zhí)行結果和上述的結果是一樣的。

          /**
           * @AUTHOR ZRH
           * @DATE 2021/4/10 0010 1:15
           */
          @FeignClient(name = "demo-user", url = "demo-user:18001")
          public interface UserFeign {

              @PostMapping("hello")
              String hello(@RequestBody String param);
          }

          ————————————————

          版權聲明:本文為CSDN博主「IAmZRH」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權協(xié)議,轉載請附上原文出處鏈接及本聲明。

          原文鏈接:

          https://blog.csdn.net/qq_41665452/article/details/115562720





          鋒哥最新SpringCloud分布式電商秒殺課程發(fā)布

          ??????

          ??長按上方微信二維碼 2 秒





          感謝點贊支持下哈 

          瀏覽 105
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄色片视频欧美 | 欧美大香蕉视频 | 日韩人妻不卡 | 四虎5151毛片 | 色婷婷色婷婷 |