You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2020/11/25 03:51:45 UTC

[servicecomb-java-chassis] branch master updated: [SCB-2125] third service support multi schemas (#2078)

This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git


The following commit(s) were added to refs/heads/master by this push:
     new b307b38  [SCB-2125] third service support multi schemas (#2078)
b307b38 is described below

commit b307b380d1c73e8d06b181972f2a83e9f3e1ad3d
Author: wujimin <wu...@huawei.com>
AuthorDate: Wed Nov 25 11:51:13 2020 +0800

    [SCB-2125] third service support multi schemas (#2078)
---
 .../core/registry/ThirdServiceRegister.java        | 179 +++++++++++++++++++++
 .../demo/springmvc/client/SpringmvcClient.java     |  11 ++
 .../demo/springmvc/client/ThirdSvc.java            |  46 ++++++
 .../src/main/resources/microservice.yaml           |   7 +-
 .../consumer/StaticMicroserviceVersions.java       |  86 +++++-----
 .../registry/ThirdServiceWithInvokerRegister.java  |  80 +++++++++
 6 files changed, 369 insertions(+), 40 deletions(-)

diff --git a/core/src/main/java/org/apache/servicecomb/core/registry/ThirdServiceRegister.java b/core/src/main/java/org/apache/servicecomb/core/registry/ThirdServiceRegister.java
new file mode 100644
index 0000000..3c76938
--- /dev/null
+++ b/core/src/main/java/org/apache/servicecomb/core/registry/ThirdServiceRegister.java
@@ -0,0 +1,179 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.servicecomb.core.registry;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.apache.servicecomb.core.BootListener;
+import org.apache.servicecomb.core.invocation.endpoint.EndpointUtils;
+import org.apache.servicecomb.registry.DiscoveryManager;
+import org.apache.servicecomb.registry.api.registry.MicroserviceInstance;
+import org.apache.servicecomb.registry.consumer.MicroserviceVersions;
+import org.apache.servicecomb.registry.consumer.StaticMicroserviceVersions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.EnvironmentAware;
+import org.springframework.core.env.Environment;
+import org.springframework.util.CollectionUtils;
+
+/**
+ * <pre>
+ * for declare a 3rd service as a servicecomb service
+ * assume a 3rd service:
+ *   1. named svc
+ *   2. have 2 address: https://svc-1 and https://svc-2
+ *   3. have 2 schemas: schema1 and schema2
+ *
+ * usage:
+ *   1. define schema interface in JAX-RS or springMVC mode
+ *     1) schema1
+ *      {@code
+ *        @Path("/v1/svc")
+ *        public interface Schema1Client {
+ *          @GET
+ *          @Path("/add")
+ *          int add(@QueryParam("q-x") int x, @QueryParam("q-y") int y);
+ *
+ *          @GET
+ *          @Path("/minus")
+ *          int minus(@QueryParam("q-x") int x, @QueryParam("q-y") int y);
+ *        }
+ *      }
+ *     2) schema2
+ *   2. add configuration to microservice.yaml
+ *      {@code
+ *        svc:
+ *          urls:
+ *            - https://svc-1
+ *            - https://svc-2
+ *      }
+ *   3. declare the 3rd service
+ *      {@code
+ *        @Configuration
+ *        public class Svc extends ThirdServiceRegister {
+ *          public static final String NAME = "svc";
+ *
+ *          public Svc() {
+ *            super(NAME);
+ *
+ *            addSchema("schema1", Schema1Client.class);
+ *            addSchema("schema2", Schema2Client.class);
+ *          }
+ *        }
+ *      }
+ * </pre>
+ */
+public abstract class ThirdServiceRegister implements BootListener, EnvironmentAware {
+  private static final Logger LOGGER = LoggerFactory.getLogger(ThirdServiceRegister.class);
+
+  public static final int ORDER = -1000;
+
+  private static final String VERSION = "1.0";
+
+  /**
+   * role: {@link EndpointUtils}<br>
+   * default to any address
+   */
+  protected List<String> urls = Collections.singletonList("http://127.0.0.1");
+
+  protected String appId;
+
+  protected final String microserviceName;
+
+  // for 3rd service, schema interface is client interface too
+  protected final Map<String, Class<?>> schemaByIdMap = new HashMap<>();
+
+  public ThirdServiceRegister(String microserviceName) {
+    this.microserviceName = microserviceName;
+  }
+
+  @Override
+  public int getOrder() {
+    return ORDER;
+  }
+
+  public List<String> getUrls() {
+    return urls;
+  }
+
+  @Override
+  public void setEnvironment(Environment environment) {
+    String urlKey = microserviceName + ".urls";
+    @SuppressWarnings("unchecked")
+    List<String> urls = environment.getProperty(urlKey, List.class);
+    setUrls(urlKey, urls);
+  }
+
+  public void setUrls(String urlKey, List<String> urls) {
+    if (CollectionUtils.isEmpty(urls)) {
+      LOGGER.warn("missing configuration, key = {}", urlKey);
+      return;
+    }
+
+    this.urls = urls;
+  }
+
+  protected void addSchema(String schemaId, Class<?> schemaCls) {
+    schemaByIdMap.put(schemaId, schemaCls);
+  }
+
+  @Override
+  public void onAfterRegistry(BootEvent event) {
+    appId = event.getScbEngine().getAppId();
+    registerMicroserviceMapping();
+  }
+
+  protected void registerMicroserviceMapping() {
+    List<String> endpoints = createEndpoints();
+    List<MicroserviceInstance> instances = createInstances(endpoints);
+
+    DiscoveryManager.INSTANCE.getAppManager()
+        .getOrCreateMicroserviceManager(appId)
+        .getVersionsByName()
+        .computeIfAbsent(microserviceName, svcName -> createMicroserviceVersions(instances));
+
+    LOGGER.info("register third service, name={}, endpoints={}.", microserviceName, endpoints);
+  }
+
+  protected List<String> createEndpoints() {
+    return urls.stream()
+        .map(EndpointUtils::formatFromUri)
+        .collect(Collectors.toList());
+  }
+
+  protected List<MicroserviceInstance> createInstances(List<String> endpoints) {
+    return endpoints.stream()
+        .map(endpoint -> {
+          MicroserviceInstance instance = new MicroserviceInstance();
+          instance.setEndpoints(Collections.singletonList(endpoint));
+          return instance;
+        })
+        .collect(Collectors.toList());
+  }
+
+  protected MicroserviceVersions createMicroserviceVersions(List<MicroserviceInstance> instances) {
+    return new StaticMicroserviceVersions(
+        DiscoveryManager.INSTANCE.getAppManager(),
+        appId,
+        microserviceName)
+        .init(schemaByIdMap, VERSION, instances);
+  }
+}
diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringmvcClient.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringmvcClient.java
index 6f7bdde..e8c31a1 100644
--- a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringmvcClient.java
+++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringmvcClient.java
@@ -17,6 +17,7 @@
 
 package org.apache.servicecomb.demo.springmvc.client;
 
+import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -26,6 +27,7 @@ import org.apache.servicecomb.demo.DemoConst;
 import org.apache.servicecomb.demo.TestMgr;
 import org.apache.servicecomb.demo.controller.Controller;
 import org.apache.servicecomb.demo.controller.Person;
+import org.apache.servicecomb.demo.springmvc.client.ThirdSvc.ThirdSvcClient;
 import org.apache.servicecomb.foundation.common.utils.BeanUtils;
 import org.apache.servicecomb.foundation.common.utils.Log4jUtils;
 import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
@@ -205,9 +207,18 @@ public class SpringmvcClient {
       testRequiredBody(templateUrlWithServiceName, microserviceName);
       testSpringMvcDefaultValuesAllTransport(templateUrlWithServiceName, microserviceName);
       testSpringMvcDefaultValuesJavaPrimitiveAllTransport(templateUrlWithServiceName, microserviceName);
+      testThirdService();
     }
   }
 
+  private static void testThirdService() {
+    ThirdSvcClient client = BeanUtils.getContext().getBean(ThirdSvcClient.class);
+
+    Date date = new Date();
+    ResponseEntity<Date> responseEntity = client.responseEntity(date);
+    TestMgr.check(date, responseEntity.getBody());
+  }
+
   private static void testControllerRest(RestTemplate template, String microserviceName) {
     String prefix = "cse://" + microserviceName;
 
diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/ThirdSvc.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/ThirdSvc.java
new file mode 100644
index 0000000..ae855e2
--- /dev/null
+++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/ThirdSvc.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.servicecomb.demo.springmvc.client;
+
+import java.util.Date;
+
+import org.apache.servicecomb.provider.pojo.registry.ThirdServiceWithInvokerRegister;
+import org.apache.servicecomb.swagger.extend.annotations.ResponseHeaders;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestAttribute;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import io.swagger.annotations.ResponseHeader;
+
+@Configuration
+public class ThirdSvc extends ThirdServiceWithInvokerRegister {
+  @RequestMapping(path = "/codeFirstSpringmvc")
+  public interface ThirdSvcClient {
+    @ResponseHeaders({@ResponseHeader(name = "h1", response = String.class),
+        @ResponseHeader(name = "h2", response = String.class)})
+    @RequestMapping(path = "/responseEntity", method = RequestMethod.POST)
+    ResponseEntity<Date> responseEntity(@RequestAttribute("date") Date date);
+  }
+
+  public ThirdSvc() {
+    super("3rd-svc");
+
+    addSchema("schema-1", ThirdSvcClient.class);
+  }
+}
diff --git a/demo/demo-springmvc/springmvc-client/src/main/resources/microservice.yaml b/demo/demo-springmvc/springmvc-client/src/main/resources/microservice.yaml
index 95b2b43..cc63f46 100644
--- a/demo/demo-springmvc/springmvc-client/src/main/resources/microservice.yaml
+++ b/demo/demo-springmvc/springmvc-client/src/main/resources/microservice.yaml
@@ -35,7 +35,7 @@ servicecomb:
           interval: 90
         watch: true
       autodiscovery: true
-# can download config center from https://cse-bucket.obs.myhwclouds.com/LocalCSE/Local-CSE-1.0.0.zip to test dynamic config
+  # can download config center from https://cse-bucket.obs.myhwclouds.com/LocalCSE/Local-CSE-1.0.0.zip to test dynamic config
   config:
     client:
       serverUri: http://127.0.0.1:30113
@@ -127,6 +127,11 @@ cse:
             timeoutInMilliseconds: 1000
   test:
     duplicate2: newer
+
+3rd-svc:
+  urls:
+    - http://localhost:8080
+
 #########SSL options
 ssl.protocols: TLSv1.2
 ssl.authPeer: true
diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/consumer/StaticMicroserviceVersions.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/consumer/StaticMicroserviceVersions.java
index 6a249e4..08f1fdd 100644
--- a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/consumer/StaticMicroserviceVersions.java
+++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/consumer/StaticMicroserviceVersions.java
@@ -18,61 +18,82 @@
 package org.apache.servicecomb.registry.consumer;
 
 import java.util.List;
-import java.util.UUID;
+import java.util.Map;
 
+import org.apache.servicecomb.registry.RegistrationManager;
 import org.apache.servicecomb.registry.api.registry.FindInstancesResponse;
 import org.apache.servicecomb.registry.api.registry.Microservice;
 import org.apache.servicecomb.registry.api.registry.MicroserviceInstance;
 import org.apache.servicecomb.registry.api.registry.MicroserviceInstances;
-import org.apache.servicecomb.registry.RegistrationManager;
 import org.apache.servicecomb.registry.version.Version;
 import org.apache.servicecomb.swagger.SwaggerUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.ImmutableMap;
+
 import io.swagger.models.Swagger;
 
 public class StaticMicroserviceVersions extends MicroserviceVersions {
-
   private static final Logger LOGGER = LoggerFactory.getLogger(StaticMicroserviceVersions.class);
 
-  private Class<?> schemaIntfCls;
-
-  private Microservice microservice = new Microservice();
+  protected final Microservice microservice = new Microservice();
 
-  private MicroserviceInstances microserviceInstances = new MicroserviceInstances();
+  protected final MicroserviceInstances microserviceInstances = new MicroserviceInstances();
 
   public StaticMicroserviceVersions(AppManager appManager, String appId, String microserviceName) {
     super(appManager, appId, microserviceName);
   }
 
   public StaticMicroserviceVersions init(Class<?> schemaIntfCls, String version,
-      List<MicroserviceInstance> addedInstances) {
-    this.schemaIntfCls = schemaIntfCls;
-    Swagger swagger = RegistrationManager.INSTANCE.getSwaggerLoader()
-        .registerSwagger(appId, shortName, shortName, schemaIntfCls);
-    String swaggerContent = SwaggerUtils.swaggerToString(swagger);
-    LOGGER.info("generate swagger for 3rd party service [{}]/[{}], swagger: {}",
-        getMicroserviceName(), version, swaggerContent);
-    microservice.addSchema(shortName, swaggerContent);
+      List<MicroserviceInstance> instances) {
+    return init(ImmutableMap.of(microserviceName, schemaIntfCls), version, instances);
+  }
 
+  public StaticMicroserviceVersions init(Map<String, Class<?>> schemaByIdMap, String version,
+      List<MicroserviceInstance> instances) {
     createMicroservice(version);
-
-    for (MicroserviceInstance instance : addedInstances) {
-      instance.setServiceId(microservice.getServiceId());
-      instance.setInstanceId(microservice.getServiceId() + "-" + UUID.randomUUID());
-    }
-    microserviceInstances.setMicroserviceNotExist(false);
-    microserviceInstances.setInstancesResponse(new FindInstancesResponse());
-    microserviceInstances.getInstancesResponse().setInstances(addedInstances);
-
+    addSchemas(schemaByIdMap);
+    addInstances(instances);
     pullInstances();
 
     return this;
   }
 
-  public Class<?> getSchemaIntfCls() {
-    return schemaIntfCls;
+  protected void createMicroservice(String version) {
+    String environment = RegistrationManager.INSTANCE.getMicroservice().getEnvironment();
+
+    microservice.setAppId(this.getAppId());
+    microservice.setServiceName(this.getShortName());
+    microservice.setVersion(new Version(version).getVersion());
+    microservice.setServiceId(this.getAppId() + "-"
+        + environment + "-"
+        + this.getMicroserviceName() + "-"
+        + microservice.getVersion());
+    microservice.setEnvironment(environment);
+  }
+
+  protected void addSchemas(Map<String, Class<?>> schemaByIdMap) {
+    schemaByIdMap.forEach(this::addSchema);
+  }
+
+  protected void addSchema(String schemaId, Class<?> schemaClass) {
+    Swagger swagger = RegistrationManager.INSTANCE.getSwaggerLoader()
+        .registerSwagger(appId, shortName, schemaId, schemaClass);
+    String swaggerContent = SwaggerUtils.swaggerToString(swagger);
+    LOGGER.debug("generate swagger for 3rd party service [{}], swagger: {}", microserviceName, swaggerContent);
+    microservice.addSchema(schemaId, swaggerContent);
+  }
+
+  protected void addInstances(List<MicroserviceInstance> instances) {
+    for (int idx = 0; idx < instances.size(); idx++) {
+      MicroserviceInstance instance = instances.get(idx);
+      instance.setServiceId(microservice.getServiceId());
+      instance.setInstanceId(microservice.getServiceId() + "-" + idx);
+    }
+    microserviceInstances.setMicroserviceNotExist(false);
+    microserviceInstances.setInstancesResponse(new FindInstancesResponse());
+    microserviceInstances.getInstancesResponse().setInstances(instances);
   }
 
   @Override
@@ -87,17 +108,4 @@ public class StaticMicroserviceVersions extends MicroserviceVersions {
   protected MicroserviceVersion createMicroserviceVersion(String microserviceId, List<MicroserviceInstance> instances) {
     return new MicroserviceVersion(this, microservice, microserviceName, instances);
   }
-
-  private void createMicroservice(String version) {
-    String environment = RegistrationManager.INSTANCE.getMicroservice().getEnvironment();
-
-    microservice.setAppId(this.getAppId());
-    microservice.setServiceName(this.getShortName());
-    microservice.setVersion(new Version(version).getVersion());
-    microservice.setServiceId(this.getAppId() + "-"
-        + environment + "-"
-        + this.getMicroserviceName() + "-"
-        + microservice.getVersion());
-    microservice.setEnvironment(environment);
-  }
 }
diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/registry/ThirdServiceWithInvokerRegister.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/registry/ThirdServiceWithInvokerRegister.java
new file mode 100644
index 0000000..f131024
--- /dev/null
+++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/registry/ThirdServiceWithInvokerRegister.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.servicecomb.provider.pojo.registry;
+
+import java.util.Map.Entry;
+
+import org.apache.servicecomb.core.registry.ThirdServiceRegister;
+import org.apache.servicecomb.provider.pojo.Invoker;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+
+/**
+ * <pre>
+ * extend {@link ThirdServiceRegister} to register consumer client bean
+ *
+ * usage:
+ *   1. declare the 3rd service
+ *      {@code
+ *        @Configuration
+ *        public class Svc extends ThirdServiceWithInvokerRegister {
+ *          public static final String NAME = "svc";
+ *
+ *          public Svc() {
+ *            super(NAME);
+ *
+ *            addSchema("schema1", Schema1Client.class);
+ *            addSchema("schema2", Schema2Client.class);
+ *          }
+ *        }
+ *      }
+ *   2. invoke the 3rd service same to normal servicecomb service
+ *      {@code
+ *        @Bean
+ *        public class SomeService {
+ *          private Schema1Client client;
+ *
+ *          @Autowired
+ *          public void setClient(Schema1Client client) {
+ *            this.client = client;
+ *          }
+ *
+ *          public int add(int x, int y) {
+ *            return client.add(x, y);
+ *          }
+ *        }
+ *      }
+ * </pre>
+ */
+public abstract class ThirdServiceWithInvokerRegister extends ThirdServiceRegister implements BeanFactoryPostProcessor {
+  public ThirdServiceWithInvokerRegister(String microserviceName) {
+    super(microserviceName);
+  }
+
+  @Override
+  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+    for (Entry<String, Class<?>> entry : schemaByIdMap.entrySet()) {
+      Object instance = createClientProxy(entry.getKey(), entry.getValue());
+      beanFactory.registerSingleton(microserviceName + "_" + entry.getKey(), instance);
+    }
+  }
+
+  protected Object createClientProxy(String schemaId, Class<?> consumerIntf) {
+    return Invoker.createProxy(microserviceName, schemaId, consumerIntf);
+  }
+}