You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by ni...@apache.org on 2019/03/07 03:08:49 UTC

[servicecomb-pack] branch master updated: [SCB-1180] Register random gRPC port to eureka instance metadata (#420)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 57c863f  [SCB-1180] Register random gRPC port to eureka instance metadata (#420)
57c863f is described below

commit 57c863f0cb841acb836f00133f208b89d2398c4e
Author: Lei Zhang <co...@gmail.com>
AuthorDate: Thu Mar 7 11:08:44 2019 +0800

    [SCB-1180] Register random gRPC port to eureka instance metadata (#420)
    
    * [SCB-1180] Replace Spring Event with Guava EventBus implement module decoupling
    
    * [SCB-1180] Remove spring-cloud-starter-netflix-eureka-client dependency from alpha-spring-boot-start-x
    
    * [SCB-1180] Add alpha-spring-cloud-starter-eureka model
    
    * [SCB-1180] Contains spring cloud eureka dependence by default
    
    * [SCB-1180] Add integration tests to register random ports to eureka
    
    * [SCB-1180] Default exposure /info /health/ /alpha endpoints
    
    * [SCB-1180] Automatically assemble the nodeStatus object using @Bean
    
    * [SCB-1180] Default exposure all actuator endpoints
    
    Default only exposure /info /health endpoints for spring boot 2.x
    Default exposure * endpoints for spring boot 1.x
---
 .../core}/event/GrpcStartableStartedEvent.java     |  9 +--
 alpha/alpha-server/pom.xml                         | 13 ++--
 .../servicecomb/pack/alpha/server/AlphaConfig.java | 22 ++++---
 .../pack/alpha/server/GrpcStartable.java           |  8 ++-
 .../src/main/resources/application.yaml            | 21 +++---
 .../alpha/server/AlphaIntegrationEventTest.java    | 65 +++++++++++++++++++
 .../pack/alpha/server/tcc/TccConfiguration.java    | 10 ++-
 .../alpha-spring-boot-1-starter/pom.xml            |  6 --
 .../alpha-spring-boot-2-starter/pom.xml            |  6 --
 .../pom.xml                                        | 30 ++++-----
 .../eureka/GrpcStartableStartedEventListener.java  | 75 ++++++++++++++++++++++
 alpha/pom.xml                                      |  1 +
 pom.xml                                            |  5 ++
 13 files changed, 208 insertions(+), 63 deletions(-)

diff --git a/alpha/alpha-server/src/main/java/org/apache/servicecomb/pack/alpha/server/event/GrpcStartableStartedEvent.java b/alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/event/GrpcStartableStartedEvent.java
similarity index 77%
rename from alpha/alpha-server/src/main/java/org/apache/servicecomb/pack/alpha/server/event/GrpcStartableStartedEvent.java
rename to alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/event/GrpcStartableStartedEvent.java
index f93ee81..21148cc 100644
--- a/alpha/alpha-server/src/main/java/org/apache/servicecomb/pack/alpha/server/event/GrpcStartableStartedEvent.java
+++ b/alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/event/GrpcStartableStartedEvent.java
@@ -15,14 +15,11 @@
  * limitations under the License.
  */
 
-package org.apache.servicecomb.pack.alpha.server.event;
+package org.apache.servicecomb.pack.alpha.core.event;
 
-import org.springframework.context.ApplicationEvent;
-
-public class GrpcStartableStartedEvent extends ApplicationEvent {
+public class GrpcStartableStartedEvent {
   private int port;
-  public GrpcStartableStartedEvent(Object source, int port) {
-    super(source);
+  public GrpcStartableStartedEvent(int port) {
     this.port = port;
   }
 
diff --git a/alpha/alpha-server/pom.xml b/alpha/alpha-server/pom.xml
index 76b1597..a61920e 100644
--- a/alpha/alpha-server/pom.xml
+++ b/alpha/alpha-server/pom.xml
@@ -77,6 +77,10 @@
     </dependency>
     <dependency>
       <groupId>org.apache.servicecomb.pack</groupId>
+      <artifactId>alpha-spring-cloud-starter-eureka</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb.pack</groupId>
       <artifactId>pack-common</artifactId>
     </dependency>
     <dependency>
@@ -289,14 +293,5 @@
         </plugins>
       </build>
     </profile>
-    <profile>
-      <id>spring-cloud-eureka</id>
-      <dependencies>
-        <dependency>
-          <groupId>org.springframework.cloud</groupId>
-          <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
-        </dependency>
-      </dependencies>
-    </profile>
   </profiles>
 </project>
diff --git a/alpha/alpha-server/src/main/java/org/apache/servicecomb/pack/alpha/server/AlphaConfig.java b/alpha/alpha-server/src/main/java/org/apache/servicecomb/pack/alpha/server/AlphaConfig.java
index 1658253..2dcc907 100644
--- a/alpha/alpha-server/src/main/java/org/apache/servicecomb/pack/alpha/server/AlphaConfig.java
+++ b/alpha/alpha-server/src/main/java/org/apache/servicecomb/pack/alpha/server/AlphaConfig.java
@@ -27,8 +27,8 @@ import java.util.concurrent.ScheduledExecutorService;
 import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
 
+import com.google.common.eventbus.EventBus;
 import org.apache.servicecomb.pack.alpha.core.*;
-import org.apache.servicecomb.pack.alpha.server.event.GrpcStartableStartedEvent;
 import org.apache.servicecomb.pack.alpha.server.tcc.GrpcTccEventService;
 import org.apache.servicecomb.pack.alpha.server.tcc.callback.TccPendingTaskRunner;
 import org.apache.servicecomb.pack.alpha.server.tcc.service.TccEventScanner;
@@ -39,6 +39,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.autoconfigure.domain.EntityScan;
 import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
@@ -61,6 +62,14 @@ public class AlphaConfig {
   @Autowired
   ApplicationContext applicationContext;
 
+  @Autowired
+  ApplicationEventPublisher applicationEventPublisher;
+
+  @Bean("alphaEventBus")
+  EventBus alphaEventBus() {
+    return new EventBus("alphaEventBus");
+  }
+
   @Bean
   Map<String, Map<String, OmegaCallback>> omegaCallbacks() {
     return new ConcurrentHashMap<>();
@@ -100,9 +109,6 @@ public class AlphaConfig {
     }
   }
 
-  @Autowired
-  NodeStatus nodeStatus;
-
   @Bean
   TxConsistentService txConsistentService(
       @Value("${alpha.event.pollingInterval:500}") int eventPollingInterval,
@@ -111,7 +117,8 @@ public class AlphaConfig {
       TxEventRepository eventRepository,
       CommandRepository commandRepository,
       TxTimeoutRepository timeoutRepository,
-      OmegaCallback omegaCallback) {
+      OmegaCallback omegaCallback,
+      NodeStatus nodeStatus) {
         if (eventScannerEnabled) {
           new EventScanner(scheduler,
               eventRepository, commandRepository, timeoutRepository,
@@ -140,11 +147,10 @@ public class AlphaConfig {
   @Bean
   ServerStartable serverStartable(GrpcServerConfig serverConfig, TxConsistentService txConsistentService,
       Map<String, Map<String, OmegaCallback>> omegaCallbacks, GrpcTccEventService grpcTccEventService,
-      TccPendingTaskRunner tccPendingTaskRunner, TccEventScanner tccEventScanner) throws IOException {
-    ServerStartable bootstrap = new GrpcStartable(serverConfig,
+      TccPendingTaskRunner tccPendingTaskRunner, TccEventScanner tccEventScanner, EventBus eventBus) throws IOException {
+    ServerStartable bootstrap = new GrpcStartable(serverConfig, eventBus,
         new GrpcTxEventEndpointImpl(txConsistentService, omegaCallbacks), grpcTccEventService);
     new Thread(bootstrap::start).start();
-    applicationContext.publishEvent(new GrpcStartableStartedEvent(this,serverConfig.getPort()));
     tccPendingTaskRunner.start();
     tccEventScanner.start();
     Runtime.getRuntime().addShutdownHook(new Thread(() -> {
diff --git a/alpha/alpha-server/src/main/java/org/apache/servicecomb/pack/alpha/server/GrpcStartable.java b/alpha/alpha-server/src/main/java/org/apache/servicecomb/pack/alpha/server/GrpcStartable.java
index db882fa..23b258e 100644
--- a/alpha/alpha-server/src/main/java/org/apache/servicecomb/pack/alpha/server/GrpcStartable.java
+++ b/alpha/alpha-server/src/main/java/org/apache/servicecomb/pack/alpha/server/GrpcStartable.java
@@ -32,6 +32,8 @@ import java.util.stream.IntStream;
 
 import javax.net.ssl.SSLException;
 
+import com.google.common.eventbus.EventBus;
+import org.apache.servicecomb.pack.alpha.core.event.GrpcStartableStartedEvent;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -43,15 +45,18 @@ import io.grpc.netty.NettyServerBuilder;
 import io.netty.handler.ssl.ClientAuth;
 import io.netty.handler.ssl.SslContextBuilder;
 import io.netty.handler.ssl.SslProvider;
+import org.springframework.context.ApplicationEventPublisher;
 
 public class GrpcStartable implements ServerStartable {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
   private Server server;
   private final GrpcServerConfig serverConfig;
+  private final EventBus eventBus;
 
-  public GrpcStartable(GrpcServerConfig serverConfig, BindableService... services) throws IOException {
+  public GrpcStartable(GrpcServerConfig serverConfig, EventBus eventBus, BindableService... services) throws IOException {
     this.serverConfig = serverConfig;
+    this.eventBus = eventBus;
     ServerBuilder<?> serverBuilder;
     try {
       OptionalInt unusedPort = findUnusedPort(serverConfig);
@@ -82,6 +87,7 @@ public class GrpcStartable implements ServerStartable {
     Runtime.getRuntime().addShutdownHook(new Thread(server::shutdown));
 
     try {
+      eventBus.post(new GrpcStartableStartedEvent(serverConfig.getPort()));
       server.start();
       server.awaitTermination();
     } catch (IOException e) {
diff --git a/alpha/alpha-server/src/main/resources/application.yaml b/alpha/alpha-server/src/main/resources/application.yaml
index bfbb5e7..e0dba9d 100644
--- a/alpha/alpha-server/src/main/resources/application.yaml
+++ b/alpha/alpha-server/src/main/resources/application.yaml
@@ -28,6 +28,19 @@ spring:
   main:
     allow-bean-definition-overriding: true
 
+eureka:
+  client:
+    enabled: false
+  instance:
+    metadataMap:
+      servicecomb-alpha-server: ${alpha.server.host}:${alpha.server.port}
+
+management:
+  endpoints:
+    web:
+      exposure:
+        include: "*"
+
 ---
 spring:
   profiles: ssl
@@ -67,11 +80,3 @@ spring:
     properties:
       eclipselink:
         ddl-generation: none
-
----
-spring:
-  profiles: spring-cloud-eureka
-eureka:
-  instance:
-    metadataMap:
-      servicecomb-alpha-server: ${alpha.server.host}:${alpha.server.port}
diff --git a/alpha/alpha-server/src/test/java/org/apache/servicecomb/pack/alpha/server/AlphaIntegrationEventTest.java b/alpha/alpha-server/src/test/java/org/apache/servicecomb/pack/alpha/server/AlphaIntegrationEventTest.java
new file mode 100644
index 0000000..0cb3804
--- /dev/null
+++ b/alpha/alpha-server/src/test/java/org/apache/servicecomb/pack/alpha/server/AlphaIntegrationEventTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.pack.alpha.server;
+
+import com.google.common.eventbus.EventBus;
+import org.apache.servicecomb.pack.alpha.core.event.GrpcStartableStartedEvent;
+import org.junit.*;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.*;
+
+import static org.apache.servicecomb.pack.alpha.server.discovery.eureka.GrpcStartableStartedEventListener.ALPHA_SERVER_GRPC_ADDRESS_KEY;
+import static org.awaitility.Awaitility.await;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.when;
+
+@RunWith(SpringRunner.class)
+@ActiveProfiles("test")
+@SpringBootTest(classes = {AlphaApplication.class, AlphaConfig.class},
+    properties = {
+        "alpha.server.host=0.0.0.0",
+        "alpha.server.port=8080",
+        "eureka.client.enabled=true"
+       })
+public class AlphaIntegrationEventTest {
+
+  @Autowired
+  private EventBus eventBus;
+
+  @MockBean
+  private EurekaInstanceConfigBean eurekaInstanceConfigBean;
+
+  @Test
+  public void eurekaInstanceConfigBeanPortUpdater(){
+    when(eurekaInstanceConfigBean.getMetadataMap()).thenReturn(new HashMap<>());
+    this.eurekaInstanceConfigBean.getMetadataMap().put(ALPHA_SERVER_GRPC_ADDRESS_KEY,"0.0.0.0:0");
+    eventBus.post(new GrpcStartableStartedEvent(9000));
+    assertThat(eurekaInstanceConfigBean.getMetadataMap().get(ALPHA_SERVER_GRPC_ADDRESS_KEY),is("0.0.0.0:9000"));
+  }
+
+}
diff --git a/alpha/alpha-server/src/test/java/org/apache/servicecomb/pack/alpha/server/tcc/TccConfiguration.java b/alpha/alpha-server/src/test/java/org/apache/servicecomb/pack/alpha/server/tcc/TccConfiguration.java
index 3441e80..514565c 100644
--- a/alpha/alpha-server/src/test/java/org/apache/servicecomb/pack/alpha/server/tcc/TccConfiguration.java
+++ b/alpha/alpha-server/src/test/java/org/apache/servicecomb/pack/alpha/server/tcc/TccConfiguration.java
@@ -17,6 +17,7 @@
 
 package org.apache.servicecomb.pack.alpha.server.tcc;
 
+import com.google.common.eventbus.EventBus;
 import org.apache.servicecomb.pack.alpha.server.GrpcServerConfig;
 import org.apache.servicecomb.pack.alpha.server.GrpcStartable;
 import org.apache.servicecomb.pack.alpha.server.ServerStartable;
@@ -44,6 +45,11 @@ public class TccConfiguration {
   private int globalTxTimeoutSeconds;
 
   @Bean
+  EventBus alphaEventBus() {
+    return new EventBus("alphaEventBus");
+  }
+
+  @Bean
   TccPendingTaskRunner tccPendingTaskRunner() {
     return new TccPendingTaskRunner(delay);
   }
@@ -60,8 +66,8 @@ public class TccConfiguration {
 
   @Bean
   ServerStartable serverStartable(GrpcServerConfig serverConfig, GrpcTccEventService grpcTccEventService,
-      TccPendingTaskRunner tccPendingTaskRunner, TccEventScanner tccEventScanner) throws IOException {
-    ServerStartable bootstrap = new GrpcStartable(serverConfig, grpcTccEventService);
+      TccPendingTaskRunner tccPendingTaskRunner, TccEventScanner tccEventScanner, EventBus eventBus) throws IOException {
+    ServerStartable bootstrap = new GrpcStartable(serverConfig, eventBus, grpcTccEventService);
     new Thread(bootstrap::start).start();
 
     tccPendingTaskRunner.start();
diff --git a/alpha/alpha-spring-boot-compatibility/alpha-spring-boot-1-starter/pom.xml b/alpha/alpha-spring-boot-compatibility/alpha-spring-boot-1-starter/pom.xml
index 32bd0b8..b393ec8 100644
--- a/alpha/alpha-spring-boot-compatibility/alpha-spring-boot-1-starter/pom.xml
+++ b/alpha/alpha-spring-boot-compatibility/alpha-spring-boot-1-starter/pom.xml
@@ -50,12 +50,6 @@
         <type>pom</type>
         <scope>import</scope>
       </dependency>
-      <!-- TODO need to change the dependency with different profile -->
-      <dependency>
-        <groupId>org.springframework.cloud</groupId>
-        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
-        <version>${spring.cloud1.version}</version>
-      </dependency>
     </dependencies>
   </dependencyManagement>
 
diff --git a/alpha/alpha-spring-boot-compatibility/alpha-spring-boot-2-starter/pom.xml b/alpha/alpha-spring-boot-compatibility/alpha-spring-boot-2-starter/pom.xml
index 32960be..c6d3a2f 100644
--- a/alpha/alpha-spring-boot-compatibility/alpha-spring-boot-2-starter/pom.xml
+++ b/alpha/alpha-spring-boot-compatibility/alpha-spring-boot-2-starter/pom.xml
@@ -50,12 +50,6 @@
         <type>pom</type>
         <scope>import</scope>
       </dependency>
-      <!-- TODO need to change the dependency with different profile -->
-      <dependency>
-        <groupId>org.springframework.cloud</groupId>
-        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
-        <version>${spring.cloud2.version}</version>
-      </dependency>
     </dependencies>
   </dependencyManagement>
 
diff --git a/alpha/alpha-spring-boot-compatibility/alpha-spring-boot-2-starter/pom.xml b/alpha/alpha-spring-cloud-starter-eureka/pom.xml
similarity index 76%
copy from alpha/alpha-spring-boot-compatibility/alpha-spring-boot-2-starter/pom.xml
copy to alpha/alpha-spring-cloud-starter-eureka/pom.xml
index 32960be..78ecbc7 100644
--- a/alpha/alpha-spring-boot-compatibility/alpha-spring-boot-2-starter/pom.xml
+++ b/alpha/alpha-spring-cloud-starter-eureka/pom.xml
@@ -20,21 +20,21 @@
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <parent>
-    <artifactId>alpha-spring-boot-compatibility</artifactId>
+    <artifactId>alpha</artifactId>
     <groupId>org.apache.servicecomb.pack</groupId>
     <version>0.4.0-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
-  <artifactId>alpha-spring-boot-starter-2</artifactId>
-  <name>Pack::Alpha::Spring Boot 2.X Starter</name>
+  <artifactId>alpha-spring-cloud-starter-eureka</artifactId>
+  <name>Pack::Alpha::Spring Cloud Starter Eureka</name>
 
   <dependencyManagement>
     <dependencies>
       <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
-        <version>${spring.boot2.version}</version>
+        <version>${spring.boot.version}</version>
         <exclusions>
           <exclusion>
             <groupId>org.json</groupId>
@@ -46,15 +46,14 @@
       <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-dependencies</artifactId>
-        <version>${spring.boot2.version}</version>
+        <version>${spring.boot.version}</version>
         <type>pom</type>
         <scope>import</scope>
       </dependency>
-      <!-- TODO need to change the dependency with different profile -->
       <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
-        <version>${spring.cloud2.version}</version>
+        <version>${spring.cloud.version}</version>
       </dependency>
     </dependencies>
   </dependencyManagement>
@@ -66,23 +65,20 @@
     </dependency>
     <dependency>
       <groupId>org.springframework.boot</groupId>
-      <artifactId>spring-boot-starter</artifactId>
-      <exclusions>
-        <exclusion>
-          <groupId>org.springframework.boot</groupId>
-          <artifactId>spring-boot-starter-logging</artifactId>
-        </exclusion>
-      </exclusions>
+      <artifactId>spring-boot-starter-test</artifactId>
     </dependency>
     <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-log4j2</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.springframework.boot</groupId>
-      <artifactId>spring-boot-starter-actuator</artifactId>
+      <groupId>org.springframework.cloud</groupId>
+      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
     </dependency>
   </dependencies>
 
-
 </project>
diff --git a/alpha/alpha-spring-cloud-starter-eureka/src/main/java/org/apache/servicecomb/pack/alpha/server/discovery/eureka/GrpcStartableStartedEventListener.java b/alpha/alpha-spring-cloud-starter-eureka/src/main/java/org/apache/servicecomb/pack/alpha/server/discovery/eureka/GrpcStartableStartedEventListener.java
new file mode 100644
index 0000000..f5b192d
--- /dev/null
+++ b/alpha/alpha-spring-cloud-starter-eureka/src/main/java/org/apache/servicecomb/pack/alpha/server/discovery/eureka/GrpcStartableStartedEventListener.java
@@ -0,0 +1,75 @@
+/*
+ * 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.pack.alpha.server.discovery.eureka;
+
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+import org.apache.servicecomb.pack.alpha.core.event.GrpcStartableStartedEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration;
+import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.lang.invoke.MethodHandles;
+
+/**
+ * Listen for GrpcStartableStartedEvent and initialize the Eureka instance metadata
+ * */
+
+@Component
+@ConditionalOnClass({EurekaClientAutoConfiguration.class})
+@ConditionalOnProperty(value = {"eureka.client.enabled"}, matchIfMissing = false)
+public class GrpcStartableStartedEventListener {
+
+  private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+  public static final String ALPHA_SERVER_GRPC_ADDRESS_KEY = "servicecomb-alpha-server";
+
+  @Autowired
+  @Qualifier("alphaEventBus")
+  EventBus eventBus;
+
+  @Autowired(required = false)
+  public EurekaInstanceConfigBean eurekaInstanceConfigBean;
+
+  @PostConstruct
+  public void init(){
+    eventBus.register(this);
+  }
+
+  /**
+   * Update grpc port to eureka instance metadata
+   * */
+  @Subscribe
+  public void listenGrpcStartableStartedEvent(GrpcStartableStartedEvent grpcStartableStartedEvent) {
+    if(eurekaInstanceConfigBean!=null && this.eurekaInstanceConfigBean.getMetadataMap().containsKey(ALPHA_SERVER_GRPC_ADDRESS_KEY)){
+      String grpcAddressValue = this.eurekaInstanceConfigBean.getMetadataMap().get(ALPHA_SERVER_GRPC_ADDRESS_KEY);
+      if(grpcAddressValue!=null && grpcAddressValue.endsWith(":0")){
+        grpcAddressValue = grpcAddressValue.replace(":0",":"+grpcStartableStartedEvent.getPort());
+        this.eurekaInstanceConfigBean.getMetadataMap().put(ALPHA_SERVER_GRPC_ADDRESS_KEY,grpcAddressValue);
+        LOG.info("Register grpc address {} to Eureka instance metadata",grpcAddressValue);
+      }
+    }
+  }
+}
diff --git a/alpha/pom.xml b/alpha/pom.xml
index 27bd8e9..7394a2a 100644
--- a/alpha/pom.xml
+++ b/alpha/pom.xml
@@ -33,6 +33,7 @@
   <modules>
     <module>alpha-core</module>
     <module>alpha-spring-boot-compatibility</module>
+    <module>alpha-spring-cloud-starter-eureka</module>
     <module>alpha-server</module>
   </modules>
 
diff --git a/pom.xml b/pom.xml
index 9343f99..31a1101 100644
--- a/pom.xml
+++ b/pom.xml
@@ -305,6 +305,11 @@
       </dependency>
       <dependency>
         <groupId>org.apache.servicecomb.pack</groupId>
+        <artifactId>alpha-spring-cloud-starter-eureka</artifactId>
+        <version>0.4.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.servicecomb.pack</groupId>
         <artifactId>pack-contract-grpc</artifactId>
         <version>0.4.0-SNAPSHOT</version>
       </dependency>