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 2018/06/21 11:22:59 UTC

[incubator-servicecomb-java-chassis] 04/04: [SCB-194] boot from BeanUtils.init will auto scan main class package

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/incubator-servicecomb-java-chassis.git

commit 9147c70ac78f2dcd1d4e629da15eb51773234f73
Author: wujimin <wu...@huawei.com>
AuthorDate: Thu Jun 21 00:14:51 2018 +0800

    [SCB-194] boot from BeanUtils.init will auto scan main class package
---
 .../main/resources/META-INF/spring/cse.bean.xml    |  2 +-
 foundations/foundation-common/pom.xml              | 19 +++--
 .../foundation/common/utils/BeanUtils.java         | 40 ++++++++++
 .../foundation/common/utils/JvmUtils.java          | 53 +++++++++++++
 .../foundation/common/utils/TestBeanUtils.java     | 90 ++++++++++++++++++++++
 .../foundation/common/utils/TestJvmUtils.java      | 71 +++++++++++++++++
 6 files changed, 269 insertions(+), 6 deletions(-)

diff --git a/core/src/main/resources/META-INF/spring/cse.bean.xml b/core/src/main/resources/META-INF/spring/cse.bean.xml
index 44817fb..8ae429a 100644
--- a/core/src/main/resources/META-INF/spring/cse.bean.xml
+++ b/core/src/main/resources/META-INF/spring/cse.bean.xml
@@ -23,7 +23,7 @@
 		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
   <context:annotation-config/>
   <!-- <context:spring-configured /> -->
-  <context:component-scan base-package="org.apache.servicecomb"/>
+  <context:component-scan base-package="${scb-scan-package:org.apache.servicecomb}"/>
 
   <bean class="org.apache.servicecomb.core.config.ConfigurationSpringInitializer">
     <property name="configId" value="config"/>
diff --git a/foundations/foundation-common/pom.xml b/foundations/foundation-common/pom.xml
index d1a369f..dced02a 100644
--- a/foundations/foundation-common/pom.xml
+++ b/foundations/foundation-common/pom.xml
@@ -48,11 +48,6 @@
       <artifactId>slf4j-api</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.slf4j</groupId>
-      <artifactId>slf4j-log4j12</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
       <groupId>log4j</groupId>
       <artifactId>log4j</artifactId>
     </dependency>
@@ -76,5 +71,19 @@
       <groupId>javax.servlet</groupId>
       <artifactId>javax.servlet-api</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>foundation-test-scaffolding</artifactId>
+    </dependency>
   </dependencies>
 </project>
diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/BeanUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/BeanUtils.java
index cb1536e..103ac79 100644
--- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/BeanUtils.java
+++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/BeanUtils.java
@@ -17,13 +17,22 @@
 
 package org.apache.servicecomb.foundation.common.utils;
 
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.aop.TargetClassAware;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.support.ClassPathXmlApplicationContext;
 
+
 public final class BeanUtils {
   public static final String DEFAULT_BEAN_RESOURCE = "classpath*:META-INF/spring/*.bean.xml";
 
+  public static final String SCB_SCAN_PACKAGE = "scb-scan-package";
+
+  private static final String SCB_PACKAGE = "org.apache.servicecomb";
+
   private static ApplicationContext context;
 
   private BeanUtils() {
@@ -33,10 +42,41 @@ public final class BeanUtils {
     init(DEFAULT_BEAN_RESOURCE);
   }
 
+
   public static void init(String... configLocations) {
+    prepareServiceCombScanPackage();
+
     context = new ClassPathXmlApplicationContext(configLocations);
   }
 
+  public static void prepareServiceCombScanPackage() {
+    Set<String> scanPackags = new LinkedHashSet<>();
+    // add exists settings
+    String exists = System.getProperty(SCB_SCAN_PACKAGE);
+    if (exists != null) {
+      for (String exist : exists.trim().split(",")) {
+        if (!exist.isEmpty()) {
+          scanPackags.add(exist.trim());
+        }
+      }
+    }
+
+    // ensure servicecomb package exist
+    scanPackags.add(SCB_PACKAGE);
+
+    // add main class package
+    Class<?> mainClass = JvmUtils.findMainClass();
+    if (mainClass != null) {
+      String pkg = mainClass.getPackage().getName();
+      if (!pkg.startsWith(SCB_PACKAGE)) {
+        scanPackags.add(pkg);
+      }
+    }
+
+    // finish
+    System.setProperty(SCB_SCAN_PACKAGE, StringUtils.join(scanPackags, ","));
+  }
+
   public static ApplicationContext getContext() {
     return context;
   }
diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JvmUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JvmUtils.java
new file mode 100644
index 0000000..e2b2b86
--- /dev/null
+++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JvmUtils.java
@@ -0,0 +1,53 @@
+/*
+ * 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.foundation.common.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.VisibleForTesting;
+
+public final class JvmUtils {
+  private static final Logger LOGGER = LoggerFactory.getLogger(JvmUtils.class);
+
+  // available for oracle jdk/ open jdk, and maybe others
+  @VisibleForTesting
+  static final String SUN_JAVA_COMMAND = "sun.java.command";
+
+  private JvmUtils() {
+  }
+
+  /**
+   *
+   * @return main class or null, never throw exception
+   */
+  public static Class<?> findMainClass() {
+    String command = System.getProperty(SUN_JAVA_COMMAND);
+    if (command == null || command.isEmpty()) {
+      return null;
+    }
+
+    // command is main class and args
+    String mainClass = command.trim().split(" ")[0];
+    try {
+      return Class.forName(mainClass);
+    } catch (Throwable e) {
+      LOGGER.warn("\"{}\" is not a valid class.", mainClass, e);
+      return null;
+    }
+  }
+}
\ No newline at end of file
diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestBeanUtils.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestBeanUtils.java
index fc7afcf..c9a28c1 100644
--- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestBeanUtils.java
+++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestBeanUtils.java
@@ -17,9 +17,15 @@
 package org.apache.servicecomb.foundation.common.utils;
 
 import org.aspectj.lang.annotation.Aspect;
+import org.junit.AfterClass;
 import org.junit.Assert;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+import mockit.Expectations;
+import mockit.Mocked;
 
 public class TestBeanUtils {
   static interface Intf {
@@ -34,6 +40,16 @@ public class TestBeanUtils {
   static class MyAspect {
   }
 
+  @BeforeClass
+  public static void setup() {
+    System.clearProperty(BeanUtils.SCB_SCAN_PACKAGE);
+  }
+
+  @AfterClass
+  public static void tearDown() {
+    System.clearProperty(BeanUtils.SCB_SCAN_PACKAGE);
+  }
+
   @Test
   public void test() {
     Intf target = new Impl();
@@ -45,4 +61,78 @@ public class TestBeanUtils {
     Assert.assertEquals(Impl.class, BeanUtils.getImplClassFromBean(proxy));
     Assert.assertEquals(Impl.class, BeanUtils.getImplClassFromBean(new Impl()));
   }
+
+  @Test
+  public void prepareServiceCombScanPackage_noExist_noMain() {
+    System.clearProperty(BeanUtils.SCB_SCAN_PACKAGE);
+    new Expectations(JvmUtils.class) {
+      {
+        JvmUtils.findMainClass();
+        result = null;
+      }
+    };
+
+    BeanUtils.prepareServiceCombScanPackage();
+
+    Assert.assertEquals("org.apache.servicecomb", System.getProperty(BeanUtils.SCB_SCAN_PACKAGE));
+  }
+
+  @Test
+  public void prepareServiceCombScanPackage_noExist_scbMain() {
+    System.clearProperty(BeanUtils.SCB_SCAN_PACKAGE);
+    new Expectations(JvmUtils.class) {
+      {
+        JvmUtils.findMainClass();
+        result = TestBeanUtils.class;
+      }
+    };
+
+    BeanUtils.prepareServiceCombScanPackage();
+
+    Assert.assertEquals("org.apache.servicecomb", System.getProperty(BeanUtils.SCB_SCAN_PACKAGE));
+  }
+
+  @Test
+  public void prepareServiceCombScanPackage_noExist_otherMain() {
+    System.clearProperty(BeanUtils.SCB_SCAN_PACKAGE);
+    new Expectations(JvmUtils.class) {
+      {
+        JvmUtils.findMainClass();
+        result = String.class;
+      }
+    };
+
+    BeanUtils.prepareServiceCombScanPackage();
+
+    Assert.assertEquals("org.apache.servicecomb,java.lang", System.getProperty(BeanUtils.SCB_SCAN_PACKAGE));
+  }
+
+  @Test
+  public void prepareServiceCombScanPackage_exist() {
+    System.setProperty(BeanUtils.SCB_SCAN_PACKAGE, "a.b,,c.d");
+    new Expectations(JvmUtils.class) {
+      {
+        JvmUtils.findMainClass();
+        result = null;
+      }
+    };
+
+    BeanUtils.prepareServiceCombScanPackage();
+
+    Assert.assertEquals("a.b,c.d,org.apache.servicecomb", System.getProperty(BeanUtils.SCB_SCAN_PACKAGE));
+  }
+
+  @Test
+  public void init(@Mocked ClassPathXmlApplicationContext context) {
+    System.clearProperty(BeanUtils.SCB_SCAN_PACKAGE);
+    new Expectations(JvmUtils.class) {
+      {
+        JvmUtils.findMainClass();
+        result = TestBeanUtils.class;
+      }
+    };
+    BeanUtils.init();
+
+    Assert.assertEquals("org.apache.servicecomb", System.getProperty(BeanUtils.SCB_SCAN_PACKAGE));
+  }
 }
diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestJvmUtils.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestJvmUtils.java
new file mode 100644
index 0000000..d16792f
--- /dev/null
+++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestJvmUtils.java
@@ -0,0 +1,71 @@
+/*
+ * 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.foundation.common.utils;
+
+import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestJvmUtils {
+  static String orgCmd = System.getProperty(JvmUtils.SUN_JAVA_COMMAND);
+
+  @Before
+  public void setup() {
+    System.clearProperty(JvmUtils.SUN_JAVA_COMMAND);
+  }
+
+  @AfterClass
+  public static void tearDown() {
+    if (orgCmd == null) {
+      System.clearProperty(JvmUtils.SUN_JAVA_COMMAND);
+      return;
+    }
+
+    System.setProperty(JvmUtils.SUN_JAVA_COMMAND, orgCmd);
+  }
+
+  @Test
+  public void findMainClass_notExist() {
+    Assert.assertNull(JvmUtils.findMainClass());
+  }
+
+  @Test
+  public void findMainClass_existButEmpty() {
+    System.setProperty(JvmUtils.SUN_JAVA_COMMAND, "");
+    Assert.assertNull(JvmUtils.findMainClass());
+  }
+
+  @Test
+  public void findMainClass_invalid() {
+    LogCollector logCollector = new LogCollector();
+
+    System.setProperty(JvmUtils.SUN_JAVA_COMMAND, "invalidCls");
+
+    Assert.assertNull(JvmUtils.findMainClass());
+    Assert.assertEquals("\"invalidCls\" is not a valid class.", logCollector.getEvents().get(0).getMessage());
+    logCollector.teardown();
+  }
+
+  @Test
+  public void findMainClass_normal() {
+    System.setProperty(JvmUtils.SUN_JAVA_COMMAND, TestJvmUtils.class.getName() + " arg");
+
+    Assert.assertEquals(TestJvmUtils.class, JvmUtils.findMainClass());
+  }
+}