diff --git a/joylive-bom/pom.xml b/joylive-bom/pom.xml
index bddffde92..06e90c134 100644
--- a/joylive-bom/pom.xml
+++ b/joylive-bom/pom.xml
@@ -253,6 +253,11 @@
joylive-router-sofarpc
${revision}
+
+ com.jd.live
+ joylive-router-grpc
+ ${revision}
+
com.jd.live
joylive-router-rocketmq5
diff --git a/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-consumer/pom.xml b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-consumer/pom.xml
new file mode 100644
index 000000000..68a94ff5c
--- /dev/null
+++ b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-consumer/pom.xml
@@ -0,0 +1,90 @@
+
+ 4.0.0
+
+ com.jd.live
+ joylive-demo-grpc
+ ${revision}
+
+
+ joylive-demo-grpc-consumer
+
+
+ 2.2.4.RELEASE
+ Hoxton.SR1
+ 1.29.0
+ 2.2.0.RELEASE
+ 2.8.0.RELEASE
+ 1.8
+ 1.8
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ ${spring.boot.version}
+ pom
+ import
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring.cloud.version}
+ pom
+ import
+
+
+ com.alibaba.cloud
+ spring-cloud-alibaba-dependencies
+ ${spring.cloud.alibaba.version}
+ pom
+ import
+
+
+
+
+
+
+
+ com.jd.live
+ joylive-demo-grpc-service-api
+ ${revision}
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+ net.devh
+ grpc-client-spring-boot-starter
+ ${grpc.spring.cloud.version}
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+
+
+ ${basedir}/target
+ joylive-demo-grpc-consumer
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ com.jd.live.agent.demo.grpc.consumer.GRpcConsumerApplication
+
+
+
+
+
+
diff --git a/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-consumer/src/main/java/com/jd/live/agent/demo/grpc/consumer/GRpcConsumerApplication.java b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-consumer/src/main/java/com/jd/live/agent/demo/grpc/consumer/GRpcConsumerApplication.java
new file mode 100644
index 000000000..ab7062414
--- /dev/null
+++ b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-consumer/src/main/java/com/jd/live/agent/demo/grpc/consumer/GRpcConsumerApplication.java
@@ -0,0 +1,13 @@
+package com.jd.live.agent.demo.grpc.consumer;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class GRpcConsumerApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(GRpcConsumerApplication.class, args);
+ }
+
+}
diff --git a/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-consumer/src/main/java/com/jd/live/agent/demo/grpc/consumer/UserServiceController.java b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-consumer/src/main/java/com/jd/live/agent/demo/grpc/consumer/UserServiceController.java
new file mode 100644
index 000000000..b432bdeea
--- /dev/null
+++ b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-consumer/src/main/java/com/jd/live/agent/demo/grpc/consumer/UserServiceController.java
@@ -0,0 +1,35 @@
+package com.jd.live.agent.demo.grpc.consumer;
+
+import com.jd.live.agent.demo.grpc.service.api.*;
+import net.devh.boot.grpc.client.inject.GrpcClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/demo")
+public class UserServiceController {
+
+ @GrpcClient("user-provider")
+ private UserServiceGrpc.UserServiceBlockingStub userServiceGrpc;
+
+ @GetMapping("/get")
+ public String get(@RequestParam("id") Integer id) {
+ UserGetRequest request = UserGetRequest.newBuilder().setId(id).build();
+ UserGetResponse response = userServiceGrpc.get(request);
+ return response.getName();
+ }
+
+ @GetMapping("/create") // 为了方便测试,实际使用 @PostMapping
+ public Integer create(@RequestParam("name") String name,
+ @RequestParam("gender") Integer gender) {
+ UserCreateRequest request = UserCreateRequest.newBuilder()
+ .setName(name)
+ .setGender(gender)
+ .build();
+ UserCreateResponse response = userServiceGrpc.create(request);
+ return response.getId();
+ }
+
+}
diff --git a/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-consumer/src/main/resources/application.yml b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-consumer/src/main/resources/application.yml
new file mode 100644
index 000000000..090228847
--- /dev/null
+++ b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-consumer/src/main/resources/application.yml
@@ -0,0 +1,20 @@
+spring:
+ application:
+ name: user-consumer # 应用名
+ cloud:
+ nacos:
+ # Nacos 作为注册中心的配置项,对应 NacosDiscoveryProperties 配置类
+ discovery:
+ server-addr: 127.0.0.1:8848 # Nacos 服务器地址
+
+grpc:
+ # gRPC 客户端配置,对应 GrpcChannelsProperties 配置类的映射
+ client:
+ user-provider:
+ #服务发现,注意本地host配置 127.0.0.1 user-provider
+ address: 'discovery:///user-provider'
+ #静态地址
+ #address: 'static://127.0.0.1:9898'
+ enableKeepAlive: true
+ keepAliveWithoutCalls: true
+ negotiationType: plaintext
diff --git a/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-consumer/src/main/resources/nacos-logback.xml b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-consumer/src/main/resources/nacos-logback.xml
new file mode 100644
index 000000000..8fc27e166
--- /dev/null
+++ b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-consumer/src/main/resources/nacos-logback.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-provider/pom.xml b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-provider/pom.xml
new file mode 100644
index 000000000..68ddc8433
--- /dev/null
+++ b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-provider/pom.xml
@@ -0,0 +1,97 @@
+
+ 4.0.0
+
+ com.jd.live
+ joylive-demo-grpc
+ ${revision}
+
+
+ joylive-demo-grpc-provider
+
+
+ 2.2.4.RELEASE
+ Hoxton.SR1
+ 1.29.0
+ 2.2.0.RELEASE
+ 2.8.0.RELEASE
+ 1.8
+ 1.8
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ ${spring.boot.version}
+ pom
+ import
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring.cloud.version}
+ pom
+ import
+
+
+ com.alibaba.cloud
+ spring-cloud-alibaba-dependencies
+ ${spring.cloud.alibaba.version}
+ pom
+ import
+
+
+
+
+
+
+
+ com.jd.live
+ joylive-demo-grpc-service-api
+ ${revision}
+
+
+
+
+ io.grpc
+ grpc-all
+ ${grpc-all.version}
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+ net.devh
+ grpc-server-spring-boot-starter
+ ${grpc.spring.cloud.version}
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+
+
+ ${basedir}/target
+ joylive-demo-grpc-provider
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ com.jd.live.agent.demo.grpc.provider.GRpcProviderApplication
+
+
+
+
+
+
diff --git a/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-provider/src/main/java/com/jd/live/agent/demo/grpc/provider/GRpcProviderApplication.java b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-provider/src/main/java/com/jd/live/agent/demo/grpc/provider/GRpcProviderApplication.java
new file mode 100644
index 000000000..8c6c22a00
--- /dev/null
+++ b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-provider/src/main/java/com/jd/live/agent/demo/grpc/provider/GRpcProviderApplication.java
@@ -0,0 +1,13 @@
+package com.jd.live.agent.demo.grpc.provider;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class GRpcProviderApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(GRpcProviderApplication.class, args);
+ }
+
+}
diff --git a/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-provider/src/main/java/com/jd/live/agent/demo/grpc/provider/UserServiceGrpcImpl.java b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-provider/src/main/java/com/jd/live/agent/demo/grpc/provider/UserServiceGrpcImpl.java
new file mode 100644
index 000000000..e50916977
--- /dev/null
+++ b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-provider/src/main/java/com/jd/live/agent/demo/grpc/provider/UserServiceGrpcImpl.java
@@ -0,0 +1,32 @@
+package com.jd.live.agent.demo.grpc.provider;
+
+import com.jd.live.agent.demo.grpc.service.api.*;
+import io.grpc.stub.StreamObserver;
+import net.devh.boot.grpc.server.service.GrpcService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@GrpcService
+public class UserServiceGrpcImpl extends UserServiceGrpc.UserServiceImplBase {
+
+ private Logger logger = LoggerFactory.getLogger(getClass());
+
+ @Override
+ public void get(UserGetRequest request, StreamObserver responseObserver) {
+ UserGetResponse.Builder builder = UserGetResponse.newBuilder();
+ builder.setId(request.getId())
+ .setName("index :" + request.getId() + " time : " + System.currentTimeMillis())
+ .setGender(request.getId() % 2 + 1);
+ responseObserver.onNext(builder.build());
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public void create(UserCreateRequest request, StreamObserver responseObserver) {
+ UserCreateResponse.Builder builder = UserCreateResponse.newBuilder();
+ builder.setId((int) (System.currentTimeMillis() / 1000));
+ responseObserver.onNext(builder.build());
+ responseObserver.onCompleted();
+ }
+
+}
diff --git a/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-provider/src/main/resources/application.yml b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-provider/src/main/resources/application.yml
new file mode 100644
index 000000000..112c9fa4d
--- /dev/null
+++ b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-provider/src/main/resources/application.yml
@@ -0,0 +1,16 @@
+spring:
+ application:
+ name: user-provider # 应用名
+ cloud:
+ nacos:
+ # Nacos 作为注册中心的配置项,对应 NacosDiscoveryProperties 配置类
+ discovery:
+ server-addr: 127.0.0.1:8848 # Nacos 服务器地址
+
+grpc:
+ # gRPC 服务器配置,对应 GrpcServerProperties 配置类
+ server:
+ port: 9898 # gRPC Server 随机端口
+
+server:
+ port: 9899 # Web Server 随机端口
diff --git a/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-provider/src/main/resources/nacos-logback.xml b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-provider/src/main/resources/nacos-logback.xml
new file mode 100644
index 000000000..8fc27e166
--- /dev/null
+++ b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-provider/src/main/resources/nacos-logback.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-service-api/pom.xml b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-service-api/pom.xml
new file mode 100644
index 000000000..6531b0ae4
--- /dev/null
+++ b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-service-api/pom.xml
@@ -0,0 +1,69 @@
+
+ 4.0.0
+
+ com.jd.live
+ joylive-demo-grpc
+ ${revision}
+
+
+ joylive-demo-grpc-service-api
+
+
+ 1.60.0
+
+ 1.8
+ 1.8
+ 1.6.2
+ 0.6.1
+ osx-x86_64
+
+
+
+
+
+ io.grpc
+ grpc-protobuf
+ ${io.grpc.version}
+
+
+
+ io.grpc
+ grpc-stub
+ ${io.grpc.version}
+
+
+
+
+
+
+
+ kr.motd.maven
+ os-maven-plugin
+ ${os-maven-plugin.version}
+
+
+
+
+
+ org.xolstice.maven.plugins
+ protobuf-maven-plugin
+ ${protobuf-maven-plugin.version}
+
+ grpc-java
+ com.google.protobuf:protoc:3.9.1:exe:${os.detected.classifier}
+ io.grpc:protoc-gen-grpc-java:${io.grpc.version}:exe:${os.detected.classifier}
+
+
+
+
+ compile
+ compile-custom
+
+
+
+
+
+
+
+
diff --git a/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-service-api/src/main/proto/UserService.proto b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-service-api/src/main/proto/UserService.proto
new file mode 100644
index 000000000..bf54d5482
--- /dev/null
+++ b/joylive-demo/joylive-demo-grpc/joylive-demo-grpc-service-api/src/main/proto/UserService.proto
@@ -0,0 +1,31 @@
+syntax = "proto3";
+option java_multiple_files = true;
+
+package com.jd.live.agent.demo.grpc.service.api;
+
+message UserGetRequest {
+ int32 id = 1;
+}
+
+message UserGetResponse {
+ int32 id = 1;
+ string name = 2;
+ int32 gender = 3;
+}
+
+message UserCreateRequest {
+ string name = 1;
+ int32 gender = 2;
+}
+
+message UserCreateResponse {
+ int32 id = 1;
+}
+
+service UserService {
+
+ rpc get(UserGetRequest) returns (UserGetResponse);
+
+ rpc create(UserCreateRequest) returns (UserCreateResponse);
+
+}
diff --git a/joylive-demo/joylive-demo-grpc/pom.xml b/joylive-demo/joylive-demo-grpc/pom.xml
new file mode 100644
index 000000000..93310b78c
--- /dev/null
+++ b/joylive-demo/joylive-demo-grpc/pom.xml
@@ -0,0 +1,109 @@
+
+ 4.0.0
+
+ com.jd.live
+ joylive-demo
+ ${revision}
+
+
+ joylive-demo-grpc
+ pom
+
+
+ 1.60.0
+ 2021.0.9
+ 2.7.18
+
+
+
+ joylive-demo-grpc-provider
+ joylive-demo-grpc-consumer
+ joylive-demo-grpc-service-api
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot.version}
+ pom
+ import
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring.cloud.version}
+ pom
+ import
+
+
+
+ io.grpc
+ grpc-all
+ ${grpc-all.version}
+ import
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+ org.springframework.boot
+ spring-boot-autoconfigure
+
+
+
+ org.springframework.boot
+ spring-boot-starter-logging
+
+
+
+ io.grpc
+ grpc-all
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+ true
+
+
+
+ org.apache.maven.plugins
+ maven-deploy-plugin
+
+ true
+
+
+
+ org.apache.maven.plugins
+ maven-install-plugin
+
+ true
+
+
+
+
+
+
diff --git a/joylive-demo/pom.xml b/joylive-demo/pom.xml
index e8ffd76e0..c8aec8c8d 100644
--- a/joylive-demo/pom.xml
+++ b/joylive-demo/pom.xml
@@ -20,6 +20,7 @@
joylive-demo-multilive
joylive-demo-rocketmq
joylive-demo-sofarpc
+ joylive-demo-grpc
diff --git a/joylive-package/pom.xml b/joylive-package/pom.xml
index bbd6a2434..d328780f0 100644
--- a/joylive-package/pom.xml
+++ b/joylive-package/pom.xml
@@ -187,6 +187,10 @@
com.jd.live
joylive-router-rocketmq4
+
+ com.jd.live
+ joylive-router-grpc
+
com.jd.live
joylive-transmission-thread
diff --git a/joylive-package/src/main/assembly/assembly.xml b/joylive-package/src/main/assembly/assembly.xml
index cb5c6e72e..5c90ea18e 100644
--- a/joylive-package/src/main/assembly/assembly.xml
+++ b/joylive-package/src/main/assembly/assembly.xml
@@ -204,6 +204,7 @@
false
com.jd.live:joylive-transmission-grpc
+ com.jd.live:joylive-router-grpc
diff --git a/joylive-plugin/joylive-router/joylive-router-grpc/pom.xml b/joylive-plugin/joylive-router/joylive-router-grpc/pom.xml
new file mode 100644
index 000000000..9de4905a1
--- /dev/null
+++ b/joylive-plugin/joylive-router/joylive-router-grpc/pom.xml
@@ -0,0 +1,42 @@
+
+ 4.0.0
+
+ com.jd.live
+ joylive-router
+ ${revision}
+
+
+ joylive-router-grpc
+
+
+ 1.60.0
+ 2.8.0.RELEASE
+ 2021.0.6.0
+
+
+
+
+
+ io.grpc
+ grpc-all
+ ${grpc-all.version}
+ provided
+
+
+
+
+ net.devh
+ grpc-spring-boot-starter
+ ${grpc-spring.version}
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+ ${alibaba-nacos-discovery.version}
+
+
+
+
diff --git a/joylive-plugin/joylive-router/joylive-router-grpc/readme.md b/joylive-plugin/joylive-router/joylive-router-grpc/readme.md
new file mode 100644
index 000000000..cabab2fce
--- /dev/null
+++ b/joylive-plugin/joylive-router/joylive-router-grpc/readme.md
@@ -0,0 +1,21 @@
+
+#�ͻ��˵���
+io.grpc.stub.ClientCalls
+#����˵���
+io.grpc.stub.ServerCalls
+
+���������������dependency, ���Գ�����ǿ��������������
+
+ io.grpc
+ grpc-stub
+ 1.30.0
+
+
+���÷�ʽ���Բο���Ŀ��SpringBoot-Labs�е� labx-30-spring-cloud-grpc
+
+
+gRpc demo���ԣ�
+
+��Ҫ�Ƚ���Ŀ�л���jdk8��Ȼ����joylive-demo-grpc-service-api����clean package�����ɳ�grpc��java�࣬
+���ɵ�ַ��target/generated-sources/protobufĿ¼�£�������Ϻ��ٽ���Ŀ�����е�jdk22���б��롣
+
diff --git a/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/cluster/AbstractClientCluster.java b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/cluster/AbstractClientCluster.java
new file mode 100644
index 000000000..ead7e69f7
--- /dev/null
+++ b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/cluster/AbstractClientCluster.java
@@ -0,0 +1,219 @@
+///*
+// * Copyright © ${year} ${owner} (${email})
+// *
+// * Licensed under the Apache License, Version 2.0 (the "License");
+// * you may not use this file except in compliance with the License.
+// * You may obtain a copy of the License at
+// *
+// * http://www.apache.org/licenses/LICENSE-2.0
+// *
+// * Unless required by applicable law or agreed to in writing, software
+// * distributed under the License is distributed on an "AS IS" BASIS,
+// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// * See the License for the specific language governing permissions and
+// * limitations under the License.
+// */
+//package com.jd.live.agent.plugin.router.gprc.cluster;
+//
+//import com.jd.live.agent.bootstrap.exception.RejectException;
+//import com.jd.live.agent.bootstrap.exception.RejectException.RejectCircuitBreakException;
+//import com.jd.live.agent.bootstrap.exception.RejectException.RejectLimitException;
+//import com.jd.live.agent.bootstrap.exception.RejectException.RejectNoProviderException;
+//import com.jd.live.agent.core.util.http.HttpMethod;
+//import com.jd.live.agent.governance.exception.RetryException.RetryExhaustedException;
+//import com.jd.live.agent.governance.invoke.OutboundInvocation;
+//import com.jd.live.agent.governance.invoke.cluster.ClusterInvoker;
+//import com.jd.live.agent.governance.invoke.cluster.LiveCluster;
+//import com.jd.live.agent.governance.policy.service.cluster.ClusterPolicy;
+//import com.jd.live.agent.governance.policy.service.cluster.RetryPolicy;
+//import com.jd.live.agent.governance.response.ServiceResponse.OutboundResponse;
+//import com.jd.live.agent.plugin.router.gprc.instance.GrpcEndpoint;
+//import com.jd.live.agent.plugin.router.gprc.request.AbstractClusterRequest;
+//import org.springframework.cloud.client.ServiceInstance;
+//import org.springframework.cloud.client.loadbalancer.CompletionContext;
+//import org.springframework.cloud.client.loadbalancer.DefaultResponse;
+//import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
+//import org.springframework.core.NestedRuntimeException;
+//import java.util.*;
+//import java.util.concurrent.CompletableFuture;
+//import java.util.concurrent.CompletionStage;
+//
+///**
+// * Provides an abstract base for implementing client clusters that can send requests and receive responses from
+// * various endpoints. This class serves as a foundation for managing a cluster of client endpoints and handling
+// * common operations such as creating HTTP headers and exceptions.
+// *
+// * @param the type of outbound requests the cluster handles
+// * @param the type of outbound responses the cluster can expect
+// */
+//public abstract class AbstractClientCluster<
+// R extends AbstractClusterRequest,
+// O extends OutboundResponse>
+// implements LiveCluster {
+//
+// @Override
+// public ClusterPolicy getDefaultPolicy(R request) {
+// if (isRetryable()) {
+// RetryPolicy retryPolicy = null;
+// LoadBalancerProperties properties = request.getProperties();
+// LoadBalancerProperties.Retry retry = properties == null ? null : properties.getRetry();
+// if (retry != null && retry.isEnabled() && (request.getHttpMethod() == HttpMethod.GET || retry.isRetryOnAllOperations())) {
+// Set statuses = new HashSet<>(retry.getRetryableStatusCodes().size());
+// retry.getRetryableStatusCodes().forEach(status -> statuses.add(String.valueOf(status)));
+// retryPolicy = new RetryPolicy();
+// retryPolicy.setRetry(retry.getMaxRetriesOnNextServiceInstance());
+// retryPolicy.setRetryInterval(retry.getBackoff().getMinBackoff().toMillis());
+// retryPolicy.setRetryStatuses(statuses);
+// }
+// return new ClusterPolicy(retryPolicy == null ? ClusterInvoker.TYPE_FAILFAST : ClusterInvoker.TYPE_FAILOVER, retryPolicy);
+// }
+// return new ClusterPolicy(ClusterInvoker.TYPE_FAILFAST);
+// }
+//
+// /**
+// * Determines if the current cluster support for retry.
+// *
+// * @return {@code true} if the operation is retryable; {@code false} otherwise.
+// */
+// protected abstract boolean isRetryable();
+//
+// /**
+// * Discover the service instances for the requested service.
+// *
+// * @param request The outbound request to be routed.
+// * @return ServiceInstance list
+// */
+// @Override
+// public CompletionStage> route(R request) {
+// CompletableFuture> future = new CompletableFuture<>();
+// ServiceInstanceListSupplier supplier = request.getInstanceSupplier();
+// if (supplier == null) {
+// future.complete(new ArrayList<>());
+// } else {
+// Mono> mono = supplier.get(request.getLbRequest()).next();
+// mono.subscribe(
+// v -> {
+// List endpoints = new ArrayList<>();
+// if (v != null) {
+// v.forEach(i -> endpoints.add(new GrpcEndpoint(i)));
+// }
+// future.complete(endpoints);
+// },
+// future::completeExceptionally
+// );
+// }
+// return future;
+// }
+//
+// @Override
+// public NestedRuntimeException createUnReadyException(String message, R request) {
+// return createException(HttpStatus.FORBIDDEN, message);
+// }
+//
+// @Override
+// public NestedRuntimeException createUnReadyException(R request) {
+// return createUnReadyException("The cluster is not ready. ", request);
+// }
+//
+// @Override
+// public NestedRuntimeException createException(Throwable throwable, R request, GrpcEndpoint endpoint) {
+// if (throwable instanceof NestedRuntimeException) {
+// return (NestedRuntimeException) throwable;
+// } else if (throwable instanceof RejectException) {
+// return createRejectException((RejectException) throwable, request);
+// }
+// return createException(HttpStatus.INTERNAL_SERVER_ERROR, throwable.getMessage(), throwable);
+// }
+//
+// @Override
+// public NestedRuntimeException createNoProviderException(R request) {
+// return createException(HttpStatus.SERVICE_UNAVAILABLE,
+// "LoadBalancer does not contain an instance for the service " + request.getService());
+// }
+//
+// @Override
+// public NestedRuntimeException createLimitException(RejectException exception, R request) {
+// return createException(HttpStatus.SERVICE_UNAVAILABLE, exception.getMessage());
+// }
+//
+// @Override
+// public NestedRuntimeException createCircuitBreakException(RejectException exception, R request) {
+// return createException(HttpStatus.SERVICE_UNAVAILABLE, exception.getMessage(), exception);
+// }
+//
+// @Override
+// public NestedRuntimeException createRejectException(RejectException exception, R request) {
+// if (exception instanceof RejectNoProviderException) {
+// return createNoProviderException(request);
+// } else if (exception instanceof RejectLimitException) {
+// return createLimitException(exception, request);
+// } else if (exception instanceof RejectCircuitBreakException) {
+// return createCircuitBreakException(exception, request);
+// }
+// return createException(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE, exception.getMessage());
+// }
+//
+// @Override
+// public NestedRuntimeException createRetryExhaustedException(RetryExhaustedException exception,
+// OutboundInvocation invocation) {
+// return createException(exception, invocation.getRequest(), null);
+// }
+//
+// @SuppressWarnings("unchecked")
+// @Override
+// public void onStart(R request) {
+// request.lifecycles(l -> l.onStart(request.getLbRequest()));
+// }
+//
+// @SuppressWarnings("unchecked")
+// @Override
+// public void onStartRequest(R request, GrpcEndpoint endpoint) {
+// request.lifecycles(l -> l.onStartRequest(request.getLbRequest(),
+// endpoint == null ? new DefaultResponse(null) : endpoint.getResponse()));
+// }
+//
+// @SuppressWarnings("unchecked")
+// @Override
+// public void onError(Throwable throwable, R request, GrpcEndpoint endpoint) {
+// request.lifecycles(l -> l.onComplete(new CompletionContext<>(
+// CompletionContext.Status.FAILED,
+// throwable,
+// request.getLbRequest(),
+// endpoint == null ? new DefaultResponse(null) : endpoint.getResponse())));
+// }
+//
+// /**
+// * Creates an {@link HttpHeaders} instance from a map of header names to lists of header values.
+// * If the input map is {@code null}, this method returns an empty {@link HttpHeaders} instance.
+// *
+// * @param headers a map of header names to lists of header values
+// * @return an {@link HttpHeaders} instance representing the provided headers
+// */
+// protected HttpHeaders getHttpHeaders(Map> headers) {
+// return headers == null ? new HttpHeaders() : new HttpHeaders(new MultiValueMapAdapter<>(headers));
+// }
+//
+// /**
+// * Creates an {@link NestedRuntimeException} using the provided status, message, and headers map.
+// *
+// * @param status the HTTP status code of the error
+// * @param message the error message
+// * @return an {@link NestedRuntimeException} instance with the specified details
+// */
+// public static NestedRuntimeException createException(HttpStatus status, String message) {
+// return createException(status, message, null);
+// }
+//
+// /**
+// * Creates an {@link NestedRuntimeException} using the provided status, message, and {@link HttpHeaders}.
+// *
+// * @param status the HTTP status code of the error
+// * @param message the error message
+// * @param throwable the exception
+// * @return an {@link NestedRuntimeException} instance with the specified details
+// */
+// public static NestedRuntimeException createException(HttpStatus status, String message, Throwable throwable) {
+// return new ResponseStatusException(status.value(), message, throwable);
+// }
+//}
+//
diff --git a/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/cluster/GrpcCluster.java b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/cluster/GrpcCluster.java
new file mode 100644
index 000000000..73dec3928
--- /dev/null
+++ b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/cluster/GrpcCluster.java
@@ -0,0 +1,73 @@
+package com.jd.live.agent.plugin.router.gprc.cluster;
+
+import com.jd.live.agent.bootstrap.exception.RejectException;
+import com.jd.live.agent.governance.exception.RetryException;
+import com.jd.live.agent.governance.invoke.OutboundInvocation;
+import com.jd.live.agent.governance.invoke.cluster.LiveCluster;
+import com.jd.live.agent.plugin.router.gprc.instance.GrpcEndpoint;
+import java.net.SocketAddress;
+import java.util.List;
+import java.util.concurrent.CompletionStage;
+import com.jd.live.agent.plugin.router.gprc.response.GrpcResponse.GrpcOutboundResponse;
+import com.jd.live.agent.plugin.router.gprc.request.GrpcRequest.GrpcOutboundRequest;
+
+
+public class GrpcCluster implements LiveCluster {
+
+ public GrpcCluster(SocketAddress socketAddress) {
+ }
+
+ @Override
+ public CompletionStage> route(GrpcOutboundRequest request) {
+ System.out.println("---->route");
+ return null;
+ }
+
+ @Override
+ public CompletionStage invoke(GrpcOutboundRequest request, GrpcEndpoint endpoint) {
+ System.out.println("---->invoke");
+ return null;
+ }
+
+ @Override
+ public GrpcOutboundResponse createResponse(Throwable throwable, GrpcOutboundRequest request, GrpcEndpoint endpoint) {
+ System.out.println("---->createResponse");
+ return null;
+ }
+
+ @Override
+ public RuntimeException createException(Throwable throwable, GrpcOutboundRequest request, GrpcEndpoint endpoint) {
+ System.out.println("---->createException");
+ return null;
+ }
+
+ @Override
+ public RuntimeException createNoProviderException(GrpcOutboundRequest request) {
+ System.out.println("---->createNoProviderException");
+ return null;
+ }
+
+ @Override
+ public RuntimeException createLimitException(RejectException exception, GrpcOutboundRequest request) {
+ System.out.println("---->createLimitException");
+ return null;
+ }
+
+ @Override
+ public RuntimeException createCircuitBreakException(RejectException exception, GrpcOutboundRequest request) {
+ System.out.println("---->createCircuitBreakException");
+ return null;
+ }
+
+ @Override
+ public RuntimeException createRejectException(RejectException exception, GrpcOutboundRequest request) {
+ System.out.println("---->createRejectException");
+ return null;
+ }
+
+ @Override
+ public RuntimeException createRetryExhaustedException(RetryException.RetryExhaustedException exception, OutboundInvocation invocation) {
+ System.out.println("---->createRetryExhaustedException");
+ return null;
+ }
+}
diff --git a/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/definition/ClusterDefinition.java b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/definition/ClusterDefinition.java
new file mode 100644
index 000000000..ec46f3fb4
--- /dev/null
+++ b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/definition/ClusterDefinition.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright © ${year} ${owner} (${email})
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jd.live.agent.plugin.router.gprc.definition;
+
+import com.jd.live.agent.core.bytekit.matcher.MatcherBuilder;
+import com.jd.live.agent.core.extension.annotation.ConditionalOnClass;
+import com.jd.live.agent.core.extension.annotation.ConditionalOnProperty;
+import com.jd.live.agent.core.extension.annotation.Extension;
+import com.jd.live.agent.core.inject.annotation.Inject;
+import com.jd.live.agent.core.inject.annotation.Injectable;
+import com.jd.live.agent.core.parser.ObjectParser;
+import com.jd.live.agent.core.plugin.definition.InterceptorDefinition;
+import com.jd.live.agent.core.plugin.definition.InterceptorDefinitionAdapter;
+import com.jd.live.agent.core.plugin.definition.PluginDefinitionAdapter;
+import com.jd.live.agent.governance.config.GovernanceConfig;
+import com.jd.live.agent.governance.invoke.InvocationContext;
+import com.jd.live.agent.plugin.router.gprc.interceptor.ClusterInterceptor;
+
+@Injectable
+@Extension(value = "GrpcClusterDefinition")
+@ConditionalOnProperty(name = GovernanceConfig.CONFIG_FLOW_CONTROL_ENABLED, matchIfMissing = true)
+@ConditionalOnProperty(name = GovernanceConfig.CONFIG_LIVE_SOFARPC_ENABLED, matchIfMissing = true)
+@ConditionalOnClass(ClusterDefinition.TYPE_ABSTRACT_CLUSTER)
+public class ClusterDefinition extends PluginDefinitionAdapter {
+
+ protected static final String TYPE_ABSTRACT_CLUSTER = "net.devh.boot.grpc.client.nameresolver.DiscoveryClientNameResolver$Resolve";
+
+ private static final String METHOD_DO_INVOKE = "Resolve";
+
+ private static final String[] ARGUMENT_DO_INVOKE = new String[]{
+
+ };
+
+ @Inject(InvocationContext.COMPONENT_INVOCATION_CONTEXT)
+ private InvocationContext context;
+
+ @Inject(ObjectParser.JSON)
+ private ObjectParser parser;
+
+ public ClusterDefinition() {
+ System.out.println("----> ClusterDefinition");
+ this.matcher = () -> MatcherBuilder.isSubTypeOf(TYPE_ABSTRACT_CLUSTER)
+ .and(MatcherBuilder.not(MatcherBuilder.isAbstract()));
+ this.interceptors = new InterceptorDefinition[]{
+ new InterceptorDefinitionAdapter(
+ MatcherBuilder.named(METHOD_DO_INVOKE)
+ .or(MatcherBuilder.arguments(ARGUMENT_DO_INVOKE)),
+ () -> new ClusterInterceptor(context, parser)
+ )
+ };
+ }
+
+}
diff --git a/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/definition/GrpcClientCallDefinition.java b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/definition/GrpcClientCallDefinition.java
new file mode 100644
index 000000000..76ef35737
--- /dev/null
+++ b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/definition/GrpcClientCallDefinition.java
@@ -0,0 +1,52 @@
+///*
+// * Copyright © ${year} ${owner} (${email})
+// *
+// * Licensed under the Apache License, Version 2.0 (the "License");
+// * you may not use this file except in compliance with the License.
+// * You may obtain a copy of the License at
+// *
+// * http://www.apache.org/licenses/LICENSE-2.0
+// *
+// * Unless required by applicable law or agreed to in writing, software
+// * distributed under the License is distributed on an "AS IS" BASIS,
+// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// * See the License for the specific language governing permissions and
+// * limitations under the License.
+// */
+//package com.jd.live.agent.plugin.router.gprc.definition;
+//
+//import com.jd.live.agent.core.bytekit.matcher.MatcherBuilder;
+//import com.jd.live.agent.core.extension.annotation.*;
+//import com.jd.live.agent.core.plugin.definition.InterceptorDefinitionAdapter;
+//import com.jd.live.agent.core.plugin.definition.PluginDefinition;
+//import com.jd.live.agent.core.plugin.definition.PluginDefinitionAdapter;
+//import com.jd.live.agent.governance.config.GovernanceConfig;
+//import com.jd.live.agent.plugin.router.gprc.interceptor.ClientCallImplInterceptor;
+//
+//@Extension(value = "GrpcClientCallDefinition", order = PluginDefinition.ORDER_TRANSMISSION)
+//@ConditionalOnProperties(value = {
+// @ConditionalOnProperty(value = GovernanceConfig.CONFIG_LIVE_ENABLED, matchIfMissing = true),
+// @ConditionalOnProperty(value = GovernanceConfig.CONFIG_LANE_ENABLED, matchIfMissing = true),
+// @ConditionalOnProperty(value = GovernanceConfig.CONFIG_FLOW_CONTROL_ENABLED, matchIfMissing = true)
+//}, relation = ConditionalRelation.OR)
+//@ConditionalOnClass(GrpcClientCallDefinition.TYPE_CLIENT_CALL_IMPL)
+//public class GrpcClientCallDefinition extends PluginDefinitionAdapter {
+//
+// public static final String TYPE_CLIENT_CALL_IMPL = "io.grpc.internal.ClientCallImpl";
+//
+// private static final String METHOD_START = "start";
+//
+// private static final String[] ARGUMENTS_START = new String[]{
+// "io.grpc.ClientCall.Listener",
+// "io.grpc.Metadata"
+// };
+//
+//
+// public GrpcClientCallDefinition() {
+// super(MatcherBuilder.named(TYPE_CLIENT_CALL_IMPL),
+// new InterceptorDefinitionAdapter(
+// MatcherBuilder.named(METHOD_START).
+// and(MatcherBuilder.arguments(ARGUMENTS_START)),
+// new ClientCallImplInterceptor()));
+// }
+//}
diff --git a/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/definition/GrpcServerCallDefinition.java b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/definition/GrpcServerCallDefinition.java
new file mode 100644
index 000000000..31cbdcc0e
--- /dev/null
+++ b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/definition/GrpcServerCallDefinition.java
@@ -0,0 +1,56 @@
+///*
+// * Copyright © ${year} ${owner} (${email})
+// *
+// * Licensed under the Apache License, Version 2.0 (the "License");
+// * you may not use this file except in compliance with the License.
+// * You may obtain a copy of the License at
+// *
+// * http://www.apache.org/licenses/LICENSE-2.0
+// *
+// * Unless required by applicable law or agreed to in writing, software
+// * distributed under the License is distributed on an "AS IS" BASIS,
+// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// * See the License for the specific language governing permissions and
+// * limitations under the License.
+// */
+//package com.jd.live.agent.plugin.router.gprc.definition;
+//
+//import com.jd.live.agent.core.bytekit.matcher.MatcherBuilder;
+//import com.jd.live.agent.core.extension.annotation.*;
+//import com.jd.live.agent.core.inject.annotation.Inject;
+//import com.jd.live.agent.core.inject.annotation.Injectable;
+//import com.jd.live.agent.core.plugin.definition.InterceptorDefinition;
+//import com.jd.live.agent.core.plugin.definition.InterceptorDefinitionAdapter;
+//import com.jd.live.agent.core.plugin.definition.PluginDefinition;
+//import com.jd.live.agent.core.plugin.definition.PluginDefinitionAdapter;
+//import com.jd.live.agent.governance.config.GovernanceConfig;
+//import com.jd.live.agent.governance.context.bag.CargoRequire;
+//import com.jd.live.agent.plugin.router.gprc.interceptor.GrpcServerInterceptor;
+//import java.util.List;
+//
+//@Injectable
+//@Extension(value = "GrpcServerCallDefinition", order = PluginDefinition.ORDER_TRANSMISSION)
+//@ConditionalOnProperties(value = {
+// @ConditionalOnProperty(value = GovernanceConfig.CONFIG_LIVE_ENABLED, matchIfMissing = true),
+// @ConditionalOnProperty(value = GovernanceConfig.CONFIG_LANE_ENABLED, matchIfMissing = true),
+// @ConditionalOnProperty(value = GovernanceConfig.CONFIG_FLOW_CONTROL_ENABLED, matchIfMissing = true)
+//}, relation = ConditionalRelation.OR)
+//@ConditionalOnClass(GrpcServerCallDefinition.TYPE_ABSTRACT_SERVER_IMPL_BUILDER)
+//public class GrpcServerCallDefinition extends PluginDefinitionAdapter {
+//
+// public static final String TYPE_ABSTRACT_SERVER_IMPL_BUILDER = "io.grpc.internal.AbstractServerImplBuilder";
+//
+// private static final String METHOD_BUILD = "build";
+//
+// @Inject
+// private List requires;
+//
+// public GrpcServerCallDefinition() {
+// this.matcher = () -> MatcherBuilder.named(TYPE_ABSTRACT_SERVER_IMPL_BUILDER);
+// this.interceptors = new InterceptorDefinition[]{
+// new InterceptorDefinitionAdapter(
+// MatcherBuilder.named(METHOD_BUILD).
+// and(MatcherBuilder.arguments(0)),
+// () -> new GrpcServerInterceptor(requires))};
+// }
+//}
diff --git a/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/instance/GrpcEndpoint.java b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/instance/GrpcEndpoint.java
new file mode 100644
index 000000000..592b3791f
--- /dev/null
+++ b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/instance/GrpcEndpoint.java
@@ -0,0 +1,40 @@
+package com.jd.live.agent.plugin.router.gprc.instance;
+
+import com.jd.live.agent.governance.instance.AbstractEndpoint;
+import com.jd.live.agent.governance.instance.EndpointState;
+import com.jd.live.agent.governance.request.ServiceRequest;
+import net.devh.boot.grpc.client.config.GrpcChannelProperties;
+
+public class GrpcEndpoint extends AbstractEndpoint {
+
+ private final GrpcChannelProperties properties;
+
+ public GrpcEndpoint(GrpcChannelProperties properties) {
+ this.properties = properties;
+ }
+
+ @Override
+ protected int computeWeight(ServiceRequest request) {
+ return 0;
+ }
+
+ @Override
+ public String getHost() {
+ return properties.getAddress().getHost();
+ }
+
+ @Override
+ public int getPort() {
+ return properties.getAddress().getPort();
+ }
+
+ @Override
+ public String getLabel(String key) {
+ return "";
+ }
+
+ @Override
+ public EndpointState getState() {
+ return null;
+ }
+}
diff --git a/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/interceptor/ClientCallImplInterceptor.java b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/interceptor/ClientCallImplInterceptor.java
new file mode 100644
index 000000000..328aad908
--- /dev/null
+++ b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/interceptor/ClientCallImplInterceptor.java
@@ -0,0 +1,34 @@
+///*
+// * Copyright © ${year} ${owner} (${email})
+// *
+// * Licensed under the Apache License, Version 2.0 (the "License");
+// * you may not use this file except in compliance with the License.
+// * You may obtain a copy of the License at
+// *
+// * http://www.apache.org/licenses/LICENSE-2.0
+// *
+// * Unless required by applicable law or agreed to in writing, software
+// * distributed under the License is distributed on an "AS IS" BASIS,
+// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// * See the License for the specific language governing permissions and
+// * limitations under the License.
+// */
+//package com.jd.live.agent.plugin.router.gprc.interceptor;
+//
+//import com.jd.live.agent.bootstrap.bytekit.context.ExecutableContext;
+//import com.jd.live.agent.core.plugin.definition.InterceptorAdaptor;
+//import com.jd.live.agent.governance.context.RequestContext;
+//import io.grpc.Metadata;
+//
+//public class ClientCallImplInterceptor extends InterceptorAdaptor {
+//
+// @Override
+// public void onEnter(ExecutableContext ctx) {
+// attachTag((Metadata) ctx.getArguments()[1]);
+// }
+//
+// private void attachTag(Metadata metadata) {
+// RequestContext.cargos(tag -> metadata.put(Metadata.Key.of(tag.getKey(), Metadata.ASCII_STRING_MARSHALLER), tag.getValue()));
+// }
+//
+//}
diff --git a/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/interceptor/ClusterInterceptor.java b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/interceptor/ClusterInterceptor.java
new file mode 100644
index 000000000..2e8bd12f0
--- /dev/null
+++ b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/interceptor/ClusterInterceptor.java
@@ -0,0 +1,51 @@
+package com.jd.live.agent.plugin.router.gprc.interceptor;
+
+import com.jd.live.agent.bootstrap.bytekit.context.ExecutableContext;
+import com.jd.live.agent.bootstrap.bytekit.context.MethodContext;
+import com.jd.live.agent.core.parser.ObjectParser;
+import com.jd.live.agent.core.plugin.definition.InterceptorAdaptor;
+import com.jd.live.agent.governance.invoke.InvocationContext;
+//import com.jd.live.agent.governance.invoke.OutboundInvocation;
+//import com.jd.live.agent.governance.response.ServiceError;
+import com.jd.live.agent.plugin.router.gprc.cluster.GrpcCluster;
+import java.net.SocketAddress;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+//import com.jd.live.agent.plugin.router.gprc.request.GrpcRequest;
+//import com.jd.live.agent.plugin.router.gprc.request.GrpcRequest.GrpcOutboundRequest;
+//import com.jd.live.agent.plugin.router.gprc.response.GrpcResponse;
+
+public class ClusterInterceptor extends InterceptorAdaptor {
+
+ private final InvocationContext context;
+
+ private final ObjectParser parser;
+
+ private final Map clusters = new ConcurrentHashMap<>();
+
+ public ClusterInterceptor(InvocationContext context, ObjectParser parser) {
+ this.context = context;
+ this.parser = parser;
+ }
+
+ @Override
+ public void onEnter(ExecutableContext ctx) {
+ MethodContext mc = (MethodContext) ctx;
+ Object[] arguments = ctx.getArguments();
+// GrpcCluster cluster = clusters.computeIfAbsent((SocketAddress) ctx.getTarget(), GrpcCluster::new);
+// GrpcOutboundRequest request = new GrpcOutboundRequest((GrpcRequest) arguments[0], cluster);
+// if (!request.isSystem() && !request.isDisabled()) {
+// OutboundInvocation.RpcOutboundInvocation invocation = new OutboundInvocation.RpcOutboundInvocation(request, context);
+// GrpcResponse.GrpcOutboundResponse response = cluster.request(invocation, null);
+// ServiceError error = response.getError();
+// if (error != null && !error.isServerError()) {
+// mc.setThrowable(error.getThrowable());
+// } else {
+// mc.setResult(response.getResponse());
+// }
+// mc.setSkip(true);
+// }
+ }
+
+}
diff --git a/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/interceptor/GrpcServerInterceptor.java b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/interceptor/GrpcServerInterceptor.java
new file mode 100644
index 000000000..92c15dc7a
--- /dev/null
+++ b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/interceptor/GrpcServerInterceptor.java
@@ -0,0 +1,63 @@
+///*
+// * Copyright © ${year} ${owner} (${email})
+// *
+// * Licensed under the Apache License, Version 2.0 (the "License");
+// * you may not use this file except in compliance with the License.
+// * You may obtain a copy of the License at
+// *
+// * http://www.apache.org/licenses/LICENSE-2.0
+// *
+// * Unless required by applicable law or agreed to in writing, software
+// * distributed under the License is distributed on an "AS IS" BASIS,
+// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// * See the License for the specific language governing permissions and
+// * limitations under the License.
+// */
+//package com.jd.live.agent.plugin.router.gprc.interceptor;
+//
+//import com.jd.live.agent.bootstrap.bytekit.context.ExecutableContext;
+//import com.jd.live.agent.core.plugin.definition.InterceptorAdaptor;
+//import com.jd.live.agent.core.util.tag.Label;
+//import com.jd.live.agent.governance.context.RequestContext;
+//import com.jd.live.agent.governance.context.bag.CargoRequire;
+//import com.jd.live.agent.governance.context.bag.CargoRequires;
+//import io.grpc.*;
+//
+//import java.util.List;
+//
+//public class GrpcServerInterceptor extends InterceptorAdaptor {
+//
+// private final CargoRequire require;
+//
+// public GrpcServerInterceptor(List requires) {
+// this.require = new CargoRequires(requires);
+// }
+//
+// @Override
+// public void onEnter(ExecutableContext ctx) {
+// Object target = ctx.getTarget();
+// if (target instanceof ServerBuilder) {
+// ((ServerBuilder>) target).intercept(new ServerInterceptor() {
+// @Override
+// public ServerCall.Listener interceptCall(
+// ServerCall call, Metadata headers, ServerCallHandler next) {
+// if (headers != null) {
+// RequestContext.create().addCargo(require, headers.keys(),
+// name -> Label.parseValue(headers.get(Metadata.Key.of(name, Metadata.ASCII_STRING_MARSHALLER))));
+// }
+// return next.startCall(new ForwardingServerCall() {
+// @Override
+// protected ServerCall delegate() {
+// return call;
+// }
+//
+// @Override
+// public MethodDescriptor getMethodDescriptor() {
+// return call.getMethodDescriptor();
+// }
+// }, headers);
+// }
+// });
+// }
+// }
+//}
diff --git a/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/request/AbstractClusterRequest.java b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/request/AbstractClusterRequest.java
new file mode 100644
index 000000000..df928bb92
--- /dev/null
+++ b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/request/AbstractClusterRequest.java
@@ -0,0 +1,242 @@
+///*
+// * Copyright © ${year} ${owner} (${email})
+// *
+// * Licensed under the Apache License, Version 2.0 (the "License");
+// * you may not use this file except in compliance with the License.
+// * You may obtain a copy of the License at
+// *
+// * http://www.apache.org/licenses/LICENSE-2.0
+// *
+// * Unless required by applicable law or agreed to in writing, software
+// * distributed under the License is distributed on an "AS IS" BASIS,
+// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// * See the License for the specific language governing permissions and
+// * limitations under the License.
+// */
+//package com.jd.live.agent.plugin.router.gprc.request;
+//
+//import com.jd.live.agent.core.util.cache.CacheObject;
+//import com.jd.live.agent.core.util.cache.UnsafeLazyObject;
+//import com.jd.live.agent.core.util.type.ClassDesc;
+//import com.jd.live.agent.core.util.type.ClassUtils;
+//import com.jd.live.agent.core.util.type.FieldDesc;
+//import com.jd.live.agent.governance.request.AbstractHttpRequest.AbstractHttpOutboundRequest;
+//import org.springframework.beans.factory.ObjectProvider;
+//import org.springframework.cloud.client.ServiceInstance;
+//import org.springframework.cloud.client.loadbalancer.*;
+//import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer;
+//import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
+//import org.springframework.http.HttpCookie;
+//import org.springframework.http.server.reactive.ServerHttpRequest;
+//import org.springframework.util.MultiValueMap;
+//
+//import java.util.HashSet;
+//import java.util.Map;
+//import java.util.Set;
+//import java.util.concurrent.ConcurrentHashMap;
+//import java.util.function.Consumer;
+//
+///**
+// * Represents an outbound HTTP request in a reactive microservices architecture,
+// * extending the capabilities of an abstract HTTP outbound request model to include
+// * client-specific functionalities. This class encapsulates features such as load balancing,
+// * service instance discovery, and lifecycle management, making it suitable for handling
+// * dynamic client requests in a distributed system.
+// */
+//public abstract class AbstractClusterRequest extends AbstractHttpOutboundRequest implements SpringClusterRequest {
+//
+// protected static final String FIELD_SERVICE_INSTANCE_LIST_SUPPLIER_PROVIDER = "serviceInstanceListSupplierProvider";
+//
+// protected static final Map> LOAD_BALANCER_LIFE_CYCLES = new ConcurrentHashMap<>();
+//
+// protected static final Map> SERVICE_INSTANCE_LIST_SUPPLIERS = new ConcurrentHashMap<>();
+//
+// /**
+// * A factory for creating instances of {@code ReactiveLoadBalancer} for service instances.
+// * This factory is used to obtain a load balancer instance for the service associated with
+// * this request.
+// */
+// protected final ReactiveLoadBalancer.Factory loadBalancerFactory;
+//
+// /**
+// * A lazy-initialized object of {@code Set}, representing the lifecycle
+// * processors for the load balancer. These processors provide hooks for custom logic at various
+// * stages of the load balancing process.
+// */
+// protected final UnsafeLazyObject> lifecycles;
+//
+// /**
+// * A lazy-initialized {@code Request>} object that encapsulates the original request data
+// * along with any hints to influence load balancing decisions.
+// */
+// protected final UnsafeLazyObject> lbRequest;
+//
+// /**
+// * A lazy-initialized {@code LoadBalancerProperties} object, containing configuration
+// * properties for load balancing.
+// */
+// protected final UnsafeLazyObject properties;
+//
+// /**
+// * A lazy-initialized {@code RequestData} object, representing the data of the original
+// * request that will be used by the load balancer to select an appropriate service instance.
+// */
+// protected final UnsafeLazyObject requestData;
+//
+// /**
+// * A lazy-initialized {@code ServiceInstanceListSupplier} object, responsible for providing
+// * a list of available service instances for load balancing.
+// */
+// protected final UnsafeLazyObject instanceSupplier;
+//
+// protected final UnsafeLazyObject stickyId;
+//
+// /**
+// * Constructs a new ClientOutboundRequest with the specified parameters.
+// *
+// * @param request The original client request to be processed.
+// * @param loadBalancerFactory A factory for creating instances of ReactiveLoadBalancer for service instances.
+// */
+// public AbstractClusterRequest(T request,
+// ReactiveLoadBalancer.Factory loadBalancerFactory) {
+// super(request);
+// this.loadBalancerFactory = loadBalancerFactory;
+// this.lifecycles = new UnsafeLazyObject<>(this::buildLifecycleProcessors);
+// this.properties = new UnsafeLazyObject<>(this::buildProperties);
+// this.lbRequest = new UnsafeLazyObject<>(this::buildLbRequest);
+// this.instanceSupplier = new UnsafeLazyObject<>(this::buildServiceInstanceListSupplier);
+// this.requestData = new UnsafeLazyObject<>(this::buildRequestData);
+// this.stickyId = new UnsafeLazyObject<>(this::buildStickyId);
+// }
+//
+// @Override
+// public String getCookie(String key) {
+// if (key == null || key.isEmpty()) {
+// return null;
+// } else if (request instanceof ServerHttpRequest) {
+// ServerHttpRequest httpRequest = (ServerHttpRequest) request;
+// HttpCookie cookie = httpRequest.getCookies().getFirst(key);
+// return cookie == null ? null : cookie.getValue();
+// } else {
+// return super.getCookie(key);
+// }
+// }
+//
+// @Override
+// public String getStickyId() {
+// return stickyId.get();
+// }
+//
+// @Override
+// public void lifecycles(Consumer consumer) {
+// if (lifecycles != null && consumer != null) {
+// lifecycles.get().forEach(consumer);
+// }
+// }
+//
+// public Request> getLbRequest() {
+// return lbRequest.get();
+// }
+//
+// public LoadBalancerProperties getProperties() {
+// return properties.get();
+// }
+//
+// public ServiceInstanceListSupplier getInstanceSupplier() {
+// return instanceSupplier.get();
+// }
+//
+// public RequestData getRequestData() {
+// return requestData.get();
+// }
+//
+// /**
+// * Creates a new {@code RequestData} object representing the data of the original request.
+// * This abstract method must be implemented by subclasses to provide specific request data
+// * for the load balancing process.
+// *
+// * @return a new {@code RequestData} object
+// */
+// protected abstract RequestData buildRequestData();
+//
+// private LoadBalancerProperties buildProperties() {
+// return loadBalancerFactory == null ? null : loadBalancerFactory.getProperties(getService());
+// }
+//
+// /**
+// * Constructs a set of lifecycle processors for the load balancer. These processors are responsible
+// * for providing custom logic that can be executed during various stages of the load balancing process,
+// * such as before and after choosing a server, and before and after the request is completed.
+// *
+// * @return A set of LoadBalancerLifecycle objects that are compatible with the current service and request/response types.
+// */
+// private Set buildLifecycleProcessors() {
+// return LOAD_BALANCER_LIFE_CYCLES.computeIfAbsent(getService(), service -> loadBalancerFactory == null
+// ? new HashSet<>()
+// : LoadBalancerLifecycleValidator.getSupportedLifecycleProcessors(
+// loadBalancerFactory.getInstances(service, LoadBalancerLifecycle.class),
+// RequestDataContext.class,
+// ResponseData.class,
+// ServiceInstance.class));
+// }
+//
+// /**
+// * Creates a new load balancer request object that encapsulates the original request data along with
+// * any hints that may influence load balancing decisions. This object is used by the load balancer to
+// * select an appropriate service instance based on the provided hints and other criteria.
+// *
+// * @return A DefaultRequest object containing the context for the load balancing operation.
+// */
+// private DefaultRequest buildLbRequest() {
+// LoadBalancerProperties properties = getProperties();
+// Map hints = properties == null ? null : properties.getHint();
+// String defaultHint = hints == null ? null : hints.getOrDefault("default", "default");
+// String hint = hints == null ? null : hints.getOrDefault(getService(), defaultHint);
+// return new DefaultRequest<>(new RequestDataContext(getRequestData(), hint));
+// }
+//
+// /**
+// * Builds a supplier of service instances for load balancing. This supplier is responsible for providing
+// * a list of available service instances that the load balancer can use to distribute the incoming requests.
+// * The supplier is obtained from the load balancer instance if it provides one.
+// *
+// * @return A ServiceInstanceListSupplier that provides a list of available service instances, or null if the
+// * load balancer does not provide such a supplier.
+// */
+// @SuppressWarnings("unchecked")
+// private ServiceInstanceListSupplier buildServiceInstanceListSupplier() {
+// return SERVICE_INSTANCE_LIST_SUPPLIERS.computeIfAbsent(getService(), service -> {
+// ReactiveLoadBalancer loadBalancer = loadBalancerFactory == null ? null : loadBalancerFactory.getInstance(getService());
+// if (loadBalancer != null) {
+// ClassDesc describe = ClassUtils.describe(loadBalancer.getClass());
+// FieldDesc field = describe.getFieldList().getField(FIELD_SERVICE_INSTANCE_LIST_SUPPLIER_PROVIDER);
+// if (field != null) {
+// ObjectProvider provider = (ObjectProvider) field.get(loadBalancer);
+// return CacheObject.of(provider.getIfAvailable());
+// }
+// }
+// return CacheObject.of(null);
+// }).get();
+//
+// }
+//
+// /**
+// * Extracts the identifier from a sticky session cookie.
+// *
+// * @return The value of the sticky session cookie if present; otherwise, {@code null}.
+// * This value is used to identify the server instance that should handle requests
+// * from this client to ensure session persistence.
+// */
+// private String buildStickyId() {
+// LoadBalancerProperties properties = getProperties();
+// if (properties != null) {
+// String instanceIdCookieName = properties.getStickySession().getInstanceIdCookieName();
+// Object context = getLbRequest().getContext();
+// if (context instanceof RequestDataContext) {
+// MultiValueMap cookies = ((RequestDataContext) context).getClientRequest().getCookies();
+// return cookies == null ? null : cookies.getFirst(instanceIdCookieName);
+// }
+// }
+// return null;
+// }
+//}
diff --git a/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/request/GrpcClusterRequest.java b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/request/GrpcClusterRequest.java
new file mode 100644
index 000000000..86dc80593
--- /dev/null
+++ b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/request/GrpcClusterRequest.java
@@ -0,0 +1,74 @@
+///*
+// * Copyright © ${year} ${owner} (${email})
+// *
+// * Licensed under the Apache License, Version 2.0 (the "License");
+// * you may not use this file except in compliance with the License.
+// * You may obtain a copy of the License at
+// *
+// * http://www.apache.org/licenses/LICENSE-2.0
+// *
+// * Unless required by applicable law or agreed to in writing, software
+// * distributed under the License is distributed on an "AS IS" BASIS,
+// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// * See the License for the specific language governing permissions and
+// * limitations under the License.
+// */
+//package com.jd.live.agent.plugin.router.gprc.request;
+//
+//import com.jd.live.agent.governance.request.HttpRequest.HttpOutboundRequest;
+//
+//import java.util.function.Consumer;
+//
+///**
+// * Defines the contract for an HTTP outbound request within a reactive microservices
+// * architecture, focusing on integration with Spring Cloud's load balancing features.
+// */
+//public interface GrpcClusterRequest extends HttpOutboundRequest {
+//
+// /**
+// * Retrieves the load balancer request object that encapsulates the original request
+// * data along with any hints that may influence load balancing decisions. This object
+// * is used by the load balancer to select an appropriate service instance based on the
+// * provided hints and other criteria.
+// *
+// * @return A {@code Request>} object containing the context for the load balancing operation.
+// */
+// Request> getLbRequest();
+//
+// /**
+// * Gets the properties associated with the load balancing operation. These properties
+// * may include configurations and hints that help tailor the load balancing behavior
+// * to the needs of the specific request or service.
+// *
+// * @return An instance of {@code LoadBalancerProperties} containing load balancing configuration.
+// */
+// LoadBalancerProperties getProperties();
+//
+// /**
+// * Obtains a supplier of service instances for load balancing. This supplier is responsible
+// * for providing a list of available service instances that the load balancer can use to
+// * distribute incoming requests. The implementation of this method is crucial for enabling
+// * dynamic service discovery and selection.
+// *
+// * @return A {@code ServiceInstanceListSupplier} that provides a list of available service instances.
+// */
+// ServiceInstanceListSupplier getInstanceSupplier();
+//
+// /**
+// * Retrieves the request data that will be used by the load balancer to make service instance
+// * selection decisions. This data typically includes the original request information and any
+// * additional metadata or hints relevant to load balancing.
+// *
+// * @return An instance of {@code RequestData} representing the data of the original request.
+// */
+// RequestData getRequestData();
+//
+// /**
+// * Executes custom logic across the set of lifecycle processors associated with the load balancer,
+// * allowing for enhanced control and monitoring of the load balancing process.
+// *
+// * @param consumer A consumer that accepts {@code LoadBalancerLifecycle} instances for processing.
+// */
+// void lifecycles(Consumer consumer);
+//}
+//
diff --git a/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/request/GrpcRequest.java b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/request/GrpcRequest.java
new file mode 100644
index 000000000..5ed686edc
--- /dev/null
+++ b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/request/GrpcRequest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright © ${year} ${owner} (${email})
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jd.live.agent.plugin.router.gprc.request;
+
+import com.jd.live.agent.governance.request.AbstractRpcRequest.AbstractRpcInboundRequest;
+import com.jd.live.agent.governance.request.AbstractRpcRequest.AbstractRpcOutboundRequest;
+import com.jd.live.agent.plugin.router.gprc.cluster.GrpcCluster;
+
+public interface GrpcRequest {
+
+ class GrpcInboundRequest extends AbstractRpcInboundRequest implements GrpcRequest {
+
+ public GrpcInboundRequest(T request) {
+ super(request);
+ }
+
+ @Override
+ public String getClientIp() {
+ return null;
+ }
+
+ @Override
+ public boolean isSystem() {
+ return false;
+ }
+ }
+
+ class GrpcOutboundRequest extends AbstractRpcOutboundRequest implements GrpcRequest {
+
+ public GrpcOutboundRequest(T request) {
+ super(request);
+
+ }
+
+ public GrpcOutboundRequest(T request, GrpcCluster cluster) {
+ super(request);
+
+ }
+
+ @Override
+ public boolean isSystem() {
+ return false;
+ }
+ }
+}
diff --git a/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/request/invoke/GrpcInvocation.java b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/request/invoke/GrpcInvocation.java
new file mode 100644
index 000000000..6603eb3fa
--- /dev/null
+++ b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/request/invoke/GrpcInvocation.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright © ${year} ${owner} (${email})
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jd.live.agent.plugin.router.gprc.request.invoke;
+
+import com.jd.live.agent.governance.invoke.InboundInvocation.RpcInboundInvocation;
+import com.jd.live.agent.governance.invoke.InvocationContext;
+import com.jd.live.agent.governance.invoke.OutboundInvocation.RpcOutboundInvocation;
+import com.jd.live.agent.plugin.router.gprc.request.GrpcRequest.GrpcOutboundRequest;
+import com.jd.live.agent.plugin.router.gprc.request.GrpcRequest.GrpcInboundRequest;
+
+public interface GrpcInvocation {
+
+ class GrpcInboundInvocation extends RpcInboundInvocation implements GrpcInvocation {
+
+ public GrpcInboundInvocation(GrpcInboundRequest request, InvocationContext context) {
+ super(request, context);
+ }
+ }
+
+ class GrpcOutboundInvocation extends RpcOutboundInvocation implements GrpcInvocation {
+
+ public GrpcOutboundInvocation(GrpcOutboundRequest request, InvocationContext context) {
+ super(request, context);
+ }
+ }
+}
diff --git a/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/response/GrpcResponse.java b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/response/GrpcResponse.java
new file mode 100644
index 000000000..7b100a2c2
--- /dev/null
+++ b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/java/com/jd/live/agent/plugin/router/gprc/response/GrpcResponse.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright © ${year} ${owner} (${email})
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jd.live.agent.plugin.router.gprc.response;
+
+import com.jd.live.agent.governance.response.AbstractRpcResponse.AbstractRpcOutboundResponse;
+import com.jd.live.agent.governance.response.ServiceError;
+import java.util.function.Predicate;
+
+/**
+ * Represents a generic response in the Dubbo RPC framework. This interface serves as a marker
+ * for responses that are specific to Dubbo's communication model, allowing for a common handling
+ * mechanism for all types of Dubbo responses.
+ */
+public interface GrpcResponse {
+
+ class GrpcOutboundResponse extends AbstractRpcOutboundResponse implements GrpcResponse {
+
+ public GrpcOutboundResponse(T response) {
+ this(response, null);
+ }
+
+ public GrpcOutboundResponse(ServiceError error, Predicate predicate) {
+ super(null, error, predicate);
+ }
+
+ public GrpcOutboundResponse(T response, Predicate predicate) {
+ super(response, null, predicate);
+ }
+ }
+}
diff --git a/joylive-plugin/joylive-router/joylive-router-grpc/src/main/resources/META-INF/services/com.jd.live.agent.core.plugin.definition.PluginDefinition b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/resources/META-INF/services/com.jd.live.agent.core.plugin.definition.PluginDefinition
new file mode 100644
index 000000000..6f023df34
--- /dev/null
+++ b/joylive-plugin/joylive-router/joylive-router-grpc/src/main/resources/META-INF/services/com.jd.live.agent.core.plugin.definition.PluginDefinition
@@ -0,0 +1,2 @@
+com.jd.live.agent.plugin.router.gprc.definition.ClusterDefinition
+#com.jd.live.agent.plugin.router.gprc.definition.GrpcClientCallDefinition
diff --git a/joylive-plugin/joylive-router/pom.xml b/joylive-plugin/joylive-router/pom.xml
index 2c88abace..d49b84e11 100644
--- a/joylive-plugin/joylive-router/pom.xml
+++ b/joylive-plugin/joylive-router/pom.xml
@@ -25,6 +25,7 @@
joylive-router-rocketmq5
joylive-router-rocketmq4
joylive-router-kafka3
+ joylive-router-grpc
\ No newline at end of file