[SCB-2514]governance rate limiting support service name match (#2909)

diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/InstanceIsolationHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/InstanceIsolationHandler.java
index c798870..85afecd 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/handler/InstanceIsolationHandler.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/InstanceIsolationHandler.java
@@ -51,7 +51,7 @@
   @Override
   protected String createKey(GovernanceRequest governanceRequest, CircuitBreakerPolicy policy) {
     return InstanceIsolationProperties.MATCH_INSTANCE_ISOLATION_KEY
-        + "." + governanceRequest.getServiceId()
+        + "." + governanceRequest.getServiceName()
         + "." + governanceRequest.getInstanceId();
   }
 
@@ -68,13 +68,13 @@
 
   @Override
   public CircuitBreakerPolicy matchPolicy(GovernanceRequest governanceRequest) {
-    if (StringUtils.isEmpty(governanceRequest.getServiceId()) || StringUtils.isEmpty(
+    if (StringUtils.isEmpty(governanceRequest.getServiceName()) || StringUtils.isEmpty(
         governanceRequest.getInstanceId())) {
       LOGGER.info("Isolation is not properly configured, service id or instance id is empty.");
       return null;
     }
     CircuitBreakerPolicy circuitBreakerPolicy =
-        instanceIsolationProperties.getParsedEntity().get(governanceRequest.getServiceId());
+        instanceIsolationProperties.getParsedEntity().get(governanceRequest.getServiceName());
 
     if (circuitBreakerPolicy == null) {
       return instanceIsolationProperties.getParsedEntity().get(DEFAULT_SERVICE_NAME);
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/marker/GovernanceRequest.java b/governance/src/main/java/org/apache/servicecomb/governance/marker/GovernanceRequest.java
index bd70dbf..a42c229 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/marker/GovernanceRequest.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/marker/GovernanceRequest.java
@@ -21,17 +21,40 @@
 import org.springframework.util.LinkedCaseInsensitiveMap;
 
 public class GovernanceRequest {
+  /**
+   headers with this request, maybe null.
+   For provider: headers indicates the request headers to me.
+   For consumer: headers indicates the request headers to the target.
+   */
   private Map<String, String> headers;
 
+  /**
+   uri with this request, maybe null.
+   For provider: uri indicates the request uri to me.
+   For consumer: uri indicates the request uri to the target.
+   */
   private String uri;
 
+  /**
+   method with this request, maybe null.
+   For provider: method indicates the request method to me.
+   For consumer: method indicates the request method to the target.
+   */
   private String method;
 
-  // instance id with request, maybe null.
+  /**
+   instance id with this request, maybe null.
+   For provider: instanceId indicates who calls me.
+   For consumer: instanceId indicates the target instance.
+   */
   private String instanceId;
 
-  // microservice id (microservice name or application name + microservice name) with this request, maybe null.
-  private String serviceId;
+  /**
+   microservice id (microservice name or application name + microservice name) with this request, maybe null.
+   For provider: serviceName indicates who calls me.
+   For consumer: serviceName indicates the target service.
+   */
+  private String serviceName;
 
   public Map<String, String> getHeaders() {
     return headers;
@@ -68,11 +91,11 @@
     this.instanceId = instanceId;
   }
 
-  public String getServiceId() {
-    return serviceId;
+  public String getServiceName() {
+    return serviceName;
   }
 
-  public void setServiceId(String serviceId) {
-    this.serviceId = serviceId;
+  public void setServiceName(String serviceName) {
+    this.serviceName = serviceName;
   }
 }
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/marker/Matcher.java b/governance/src/main/java/org/apache/servicecomb/governance/marker/Matcher.java
index 95184a4..f0a70cd 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/marker/Matcher.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/marker/Matcher.java
@@ -30,11 +30,22 @@
 
   private List<String> method;
 
+  private String serviceName;
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
   public Map<String, RawOperator> getHeaders() {
     return headers;
   }
 
-  public void setHeaders(Map<String, RawOperator> headers) {
+  public void setHeaders(
+      Map<String, RawOperator> headers) {
     this.headers = headers;
   }
 
@@ -54,11 +65,11 @@
     this.method = method;
   }
 
-  public String getName() {
-    return name;
+  public String getServiceName() {
+    return serviceName;
   }
 
-  public void setName(String name) {
-    this.name = name;
+  public void setServiceName(String serviceName) {
+    this.serviceName = serviceName;
   }
 }
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/marker/RequestProcessor.java b/governance/src/main/java/org/apache/servicecomb/governance/marker/RequestProcessor.java
index 95f26b8..db03b9d 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/marker/RequestProcessor.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/marker/RequestProcessor.java
@@ -24,6 +24,9 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+/**
+ * Request Processor checks if a request matches a configuration.
+ */
 public class RequestProcessor {
 
   private static final Logger LOGGER = LoggerFactory.getLogger(RequestProcessor.class);
@@ -37,10 +40,26 @@
   }
 
   public boolean match(GovernanceRequest request, Matcher matcher) {
-    if ((matcher.getMethod() != null && !matcher.getMethod().contains(request.getMethod())) ||
-        (matcher.getApiPath() != null && !operatorMatch(request.getUri(), matcher.getApiPath()))) {
+    if (!methodMatch(request, matcher)) {
       return false;
     }
+    if (!apiPathMatch(request, matcher)) {
+      return false;
+    }
+    if (!headersMatch(request, matcher)) {
+      return false;
+    }
+    return serviceNameMatch(request, matcher);
+  }
+
+  private boolean serviceNameMatch(GovernanceRequest request, Matcher matcher) {
+    if (matcher.getServiceName() == null) {
+      return true;
+    }
+    return matcher.getServiceName().equals(request.getServiceName());
+  }
+
+  private boolean headersMatch(GovernanceRequest request, Matcher matcher) {
     if (matcher.getHeaders() == null) {
       return true;
     }
@@ -53,6 +72,20 @@
     return true;
   }
 
+  private boolean apiPathMatch(GovernanceRequest request, Matcher matcher) {
+    if (matcher.getApiPath() == null) {
+      return true;
+    }
+    return operatorMatch(request.getUri(), matcher.getApiPath());
+  }
+
+  private boolean methodMatch(GovernanceRequest request, Matcher matcher) {
+    if (matcher.getMethod() == null) {
+      return true;
+    }
+    return matcher.getMethod().contains(request.getMethod());
+  }
+
   private boolean operatorMatch(String str, RawOperator rawOperator) {
     if (rawOperator.isEmpty()) {
       return false;
@@ -61,7 +94,7 @@
     for (Entry<String, String> entry : rawOperator.entrySet()) {
       MatchOperator operator = operatorMap.get(entry.getKey() + OPERATOR_SUFFIX);
       if (operator == null) {
-        LOGGER.error("unsupported operator:" + entry.getKey() + ", plz use one of :" + operatorMap.keySet().toString());
+        LOGGER.error("unsupported operator:" + entry.getKey() + ", please use one of :" + operatorMap.keySet());
         return false;
       }
       if (!operator.match(str, entry.getValue())) {
diff --git a/governance/src/test/java/org/apache/servicecomb/governance/FlowControlTest.java b/governance/src/test/java/org/apache/servicecomb/governance/FlowControlTest.java
index 3a6288f..52d067a 100644
--- a/governance/src/test/java/org/apache/servicecomb/governance/FlowControlTest.java
+++ b/governance/src/test/java/org/apache/servicecomb/governance/FlowControlTest.java
@@ -23,7 +23,6 @@
 
 import org.apache.servicecomb.governance.handler.RateLimitingHandler;
 import org.apache.servicecomb.governance.marker.GovernanceRequest;
-import org.apache.servicecomb.governance.properties.RateLimitProperties;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -40,33 +39,17 @@
 public class FlowControlTest {
   private RateLimitingHandler rateLimitingHandler;
 
-  private RateLimitProperties rateLimitProperties;
-
-  private MatchersManager matchersManager;
-
   @Autowired
   public void setRateLimitingHandler(RateLimitingHandler rateLimitingHandler) {
     this.rateLimitingHandler = rateLimitingHandler;
   }
 
-  @Autowired
-  public void setRateLimitProperties(RateLimitProperties rateLimitProperties) {
-    this.rateLimitProperties = rateLimitProperties;
-  }
-
-  @Autowired
-  public void setMatchersManager(MatchersManager matchersManager) {
-    this.matchersManager = matchersManager;
-  }
-
   public FlowControlTest() {
   }
 
   @Test
   public void test_rate_limiting_work() throws Throwable {
-    DecorateCheckedSupplier<Object> ds = Decorators.ofCheckedSupplier(() -> {
-      return "test";
-    });
+    DecorateCheckedSupplier<Object> ds = Decorators.ofCheckedSupplier(() -> "test");
 
     GovernanceRequest request = new GovernanceRequest();
     request.setUri("/hello");
@@ -81,23 +64,60 @@
     AtomicBoolean expected = new AtomicBoolean(false);
     AtomicBoolean notExpected = new AtomicBoolean(false);
     for (int i = 0; i < 10; i++) {
-      new Thread() {
-        public void run() {
-          try {
-            Object result = ds.get();
-            if (!"test".equals(result)) {
-              notExpected.set(true);
-            }
-          } catch (Throwable e) {
-            if (e instanceof RequestNotPermitted) {
-              expected.set(true);
-            } else {
-              notExpected.set(true);
-            }
+      new Thread(() -> {
+        try {
+          Object result = ds.get();
+          if (!"test".equals(result)) {
+            notExpected.set(true);
           }
-          cd.countDown();
+        } catch (Throwable e) {
+          if (e instanceof RequestNotPermitted) {
+            expected.set(true);
+          } else {
+            notExpected.set(true);
+          }
         }
-      }.start();
+        cd.countDown();
+      }).start();
+    }
+    cd.await(1, TimeUnit.SECONDS);
+    Assertions.assertTrue(expected.get());
+    Assertions.assertFalse(notExpected.get());
+  }
+
+  @Test
+  public void test_rate_limiting_service_name_work() throws Throwable {
+    DecorateCheckedSupplier<Object> ds = Decorators.ofCheckedSupplier(() -> "test");
+
+    GovernanceRequest request = new GovernanceRequest();
+    request.setUri("/helloServiceName");
+    request.setServiceName("srcService");
+
+    RateLimiter rateLimiter = rateLimitingHandler.getActuator(request);
+    ds.withRateLimiter(rateLimiter);
+
+    Assertions.assertEquals("test", ds.get());
+
+    // flow control
+    CountDownLatch cd = new CountDownLatch(10);
+    AtomicBoolean expected = new AtomicBoolean(false);
+    AtomicBoolean notExpected = new AtomicBoolean(false);
+    for (int i = 0; i < 10; i++) {
+      new Thread(() -> {
+        try {
+          Object result = ds.get();
+          if (!"test".equals(result)) {
+            notExpected.set(true);
+          }
+        } catch (Throwable e) {
+          if (e instanceof RequestNotPermitted) {
+            expected.set(true);
+          } else {
+            notExpected.set(true);
+          }
+        }
+        cd.countDown();
+      }).start();
     }
     cd.await(1, TimeUnit.SECONDS);
     Assertions.assertTrue(expected.get());
diff --git a/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java b/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java
index 6f6bbc0..aaec8e1 100644
--- a/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java
+++ b/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java
@@ -159,7 +159,7 @@
   @Test
   public void test_match_properties_successfully_loaded() {
     Map<String, TrafficMarker> markers = matchProperties.getParsedEntity();
-    Assertions.assertEquals(4, markers.size());
+    Assertions.assertEquals(5, markers.size());
     TrafficMarker demoRateLimiting = markers.get("demo-rateLimiting");
     List<Matcher> matchers = demoRateLimiting.getMatches();
     Assertions.assertEquals(1, matchers.size());
@@ -177,17 +177,17 @@
   @Test
   public void test_match_properties_delete() {
     Map<String, TrafficMarker> markers = matchProperties.getParsedEntity();
-    Assertions.assertEquals(4, markers.size());
+    Assertions.assertEquals(5, markers.size());
     dynamicValues.put("servicecomb.matchGroup.test", "matches:\n"
         + "  - apiPath:\n"
         + "      exact: \"/hello2\"\n"
         + "    name: match0");
     GovernanceEventManager.post(new GovernanceConfigurationChangedEvent(new HashSet<>(dynamicValues.keySet())));
     markers = matchProperties.getParsedEntity();
-    Assertions.assertEquals(5, markers.size());
+    Assertions.assertEquals(6, markers.size());
     tearDown();
     markers = matchProperties.getParsedEntity();
-    Assertions.assertEquals(4, markers.size());
+    Assertions.assertEquals(5, markers.size());
   }
 
   @Test
@@ -204,7 +204,7 @@
     GovernanceEventManager.post(new GovernanceConfigurationChangedEvent(new HashSet<>(dynamicValues.keySet())));
 
     Map<String, TrafficMarker> markers = matchProperties.getParsedEntity();
-    Assertions.assertEquals(5, markers.size());
+    Assertions.assertEquals(6, markers.size());
     TrafficMarker demoRateLimiting = markers.get("demo-rateLimiting");
     List<Matcher> matchers = demoRateLimiting.getMatches();
     Assertions.assertEquals(1, matchers.size());
@@ -344,7 +344,7 @@
   @Test
   public void test_rate_limit_properties_successfully_loaded() {
     Map<String, RateLimitingPolicy> policies = rateLimitProperties.getParsedEntity();
-    Assertions.assertEquals(1, policies.size());
+    Assertions.assertEquals(2, policies.size());
     RateLimitingPolicy policy = policies.get("demo-rateLimiting");
     Assertions.assertEquals(1, policy.getRate());
   }
diff --git a/governance/src/test/java/org/apache/servicecomb/governance/InstanceIsolationTest.java b/governance/src/test/java/org/apache/servicecomb/governance/InstanceIsolationTest.java
index fa24219..86b19bf 100644
--- a/governance/src/test/java/org/apache/servicecomb/governance/InstanceIsolationTest.java
+++ b/governance/src/test/java/org/apache/servicecomb/governance/InstanceIsolationTest.java
@@ -66,7 +66,7 @@
 
     GovernanceRequest request = new GovernanceRequest();
     request.setInstanceId("instance01");
-    request.setServiceId("service01");
+    request.setServiceName("service01");
 
     CircuitBreaker circuitBreaker = instanceIsolationHandler.getActuator(request);
     ds.withCircuitBreaker(circuitBreaker);
@@ -85,7 +85,7 @@
     // isolation do not influence other instances
     GovernanceRequest request2 = new GovernanceRequest();
     request2.setInstanceId("instance02");
-    request2.setServiceId("service01");
+    request2.setServiceName("service01");
 
     CircuitBreaker circuitBreaker2 = instanceIsolationHandler.getActuator(request2);
     ds2.withCircuitBreaker(circuitBreaker2);
diff --git a/governance/src/test/resources/application.yaml b/governance/src/test/resources/application.yaml
index 6891f69..b76e489 100644
--- a/governance/src/test/resources/application.yaml
+++ b/governance/src/test/resources/application.yaml
@@ -21,6 +21,11 @@
       matches:
         - apiPath:
             exact: "/hello"
+    demo-rateLimiting-servicename: |
+      matches:
+        - apiPath:
+            exact: "/helloServiceName"
+          serviceName: "srcService"
     wrong-name-inogred: |
       wrong: some
     demo-retry: |
@@ -48,6 +53,8 @@
   rateLimiting:
     demo-rateLimiting: |
       rate: 1
+    demo-rateLimiting-servicename: |
+      rate: 1
     wrongIngored: |
       rate: 0
   retry: