摘要

阿里的Pandora Boot的核心是Pandora,因此在介绍Pandora Boot之前需要先介绍Pandora。在阿里集体内部,几乎所有的应用都用到了各式各样的中间件,比如HSF、TDDL、Diamond等等。本身中间件之间可能就有版本依赖的问题,比如你的应用HSF和Diamond分别依赖了同名jar包的不同版本,maven只会引入其中一个版本。同样的中间件和应用之间也存在同样的Jar包依赖的问题,出于要解决这些依赖冲突的问题,阿里就开发了Pandora。简单的来说就是一个类隔离容器,对外以taobao-hsf.sar这样的sar包的形式对外呈现。

一、Alibaba-pandora boot背景

Pandora主要解决的问题就是依赖冲突问题,在阿里集体内部,几乎所有的应用都用到了各式各样的中间件,比如HSF、TDDL、Diamond等等。本身中间件之间可能就有版本依赖的问题。例如:

  1. 二方包、三方包冲突: 由于版本不一致可能导致应用起不来。
  2. 冲突排查浪费大量时间:应用起不来的时候可能只是应用开发自己折腾半天在排包,但如果是二方包冲突,那么中间件团队可能就要花大量时间在答疑上面,和应用开发一起折腾了。
  3. 应用难以保持稳定:折腾半天应用终于跑起来了,但是更可怕的就是现在能跑,到了某个点某个场景可能就出bug了。
  4. 中间件升级困难:如果要实时升级中间件到推荐版本,但是发现并没有那么容易,应用中引入了十个八个中间件,隔三差五其中一个中间件就有小版本更新,每天盯着中间件的更新情况,那还有时间关心业务的开发了。

二、Alibaba-pandora boot的功能

  1. 实现类隔离,提供稳定的运行环境:Pandora实现了应用与中间件之间隔离、中间件与中间件之间隔离,保证了类的正确加载,而不会让依赖关系与依赖加载出现不一一对应的情况。
  2. 中间件平滑升级:由于应用服务器会优先加载Pandora的类,因此只要升级Pandora中的插件即可,无需对应用中的pom.xml进行修改。只需要在aone上面提交一个“HSF变更”即可。
  3. 中间件统一管理:Pandora会统一管理中间的启动、初始化以及资源回收等一系列操作。

PandoraBoot是在Pandora的基础之上,发展处的更轻量使用集团中间件的方式;它基于Pandora和Fat Jar基础,可以可以在IDE里启动Pandora环境,开发调试等效率大大提高。也就是PandoraBoot是Pandora与Spring Boot结合的产物,可以方便的享受Spring Boot社区带来的便利。

2.1 PandoraBoot与SpringBoot的联系和区别

两者联系:

  1. PandoraBoot是运行中在SpringBoot上的,完全兼容。对PandoraBoot来说SpringBoot就像是一个依赖或者简单的Main函数应用。

两者区别:

  1. Spring Boot 通过 Maven 来管理依赖,是平板化的,最前面提到的二方包、三方包依赖问题,SpringBoot解决不了。
  2. Pandora Boot很好的管理了中间件应用,用户可以快速的引入各类中间件,平滑的保持中间件升级。这两者说到底也就是集成了 Pandora 的类隔离技术。
  3. Pandora Boot 目前很好的集成了 autoconfig,外部也和 AONE2、PSP 等系统进行打通,开发起来更加的方便。

三、Alibaba-pandora boot的原理

四、Alibaba-pandora boot的实战演示

4.1 环境配置

4.1.1 安装轻量服务注册与发现中心

开发者可以在本地使用轻量级配置及注册中心实现应用的注册、发现和配置管理,完成应用的开发和测试。在将应用部署到EDAS后,这些功能仍然可以正常使用。

不同的系统下载不同的版本

  • Windows:
  1. 下载轻量级配置及注册中心压缩包
  2. 在本地解压压缩包。
  • Unix/macOS:
  1. 执行命令wget http://edas.oss-cn-hangzhou.aliyuncs.com/edas-res/edas-lightweight-server-1.0.0.tar.gz下载轻量级配置及注册中心压缩包。
  2. 执行命令 tar -zvxf edas-lightweight-server-1.0.0.tar.gz解压压缩包。

启动轻量级配置及注册中心

  • Windows:
  1. 进入目录edas-lightweight\bin
  2. 启动轻量级配置及注册中心,并查看启动结果。
  3. Windows:双击startup.bat

  • Unix/macOS
  1. Unix/macOS:执行sh startup.sh
 /usr/java/jdk1.8.0/bin/java -server -Xms1g -Xmx1g -Xmn512m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/root/service/edas-lightweight/logs/java_heapdump.hprof -XX:-UseLargePages -Djava.ext.dirs=/usr/java/jdk1.8.0/jre/lib/ext:/usr/java/jdk1.8.0/lib/ext:/root/service/edas-lightweight/plugins/cmdb:/root/service/edas-lightweight/plugins/mysql -Xloggc:/root/service/edas-lightweight/logs/nacos_gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -Dnacos.home=/root/service/edas-lightweight -Dnacos.standalone=true -jar /root/service/edas-lightweight/target/edas-lightweight.jar --spring.config.location=classpath:/,classpath :/config/,file:./,file:./config/,file:/root/service/edas-lightweight/conf/ --logging.config=/root/service/edas-lightweight/conf/nacos-logback.xml --server.max-http-header-size=524288
2. edas lightweight is starting with standalone
3. edas lightweight is starting,you can check the /root/edas-lightweight/logs/start.out

检查轻量级配置及注册中心的启动监听端口。正常启动后,会在本节点上监听以下三个端口:

  • 8848:用来支持基于Nacos应用的配置管理及服务注册。
  • 9600:HSF/Dubbo的服务注册及订阅。
  • 8080:支持ANS的服务注册以及ACM的配置管理。

Linux/macOS操作系统环境,可使用netstat -an | grep -E "8080|8848|9600" | grep -i listen命令查看上述三个端口是否处在监听状态(Linux操作系统还可以使用netstat -nltp | grep -E "8080|8848|9600"来检查这三个端口的打开情况以及是否是轻量级配置及注册中心的进程打开的)。

在本地开发环境中配置hosts

在需要使用轻量级配置及注册中心开发、测试应用的机器上配置轻量级配置及注册中心的hosts,即在DNS(hosts文件)中将jmenv.tbsite.net域名指向启动了轻量级配置及注册中心的机器IP。

  1. 打开hosts文件。
    • Windows操作系统:C:\Windows\System32\drivers\etc\hosts。
    • Unix/macOS操作系统:/etc/hosts。
  2. 添加轻量级配置及注册中心配置。
    • 如果在IP为192.168.1.100的机器上启动了轻量级配置及注册中心,则需要在hosts文件里加入配置:192.168.1.100 jmenv.tbsite.net
    • 如果在本地启动轻量级配置及注册中心,则在hosts文件中配置将上面的IP改为127.0.0.1 jmenv.tbsite.net

注册与发现配置环境测试

  • 本机

    在浏览器中输入轻量级配置及注册中心地址http://127.0.0.1:8080并回车。

  • 独立机器

    在浏览器中输入轻量级配置及注册中心地址http://机器 IP 地址:8080并回车。

如果首页不能正常显示,可以查看安装目录下的启动日志文件logs/start.log定位启动失败的原因,并修复。

4.1.2 Maven中配置 EDAS 的私服地址

目前Spring Cloud for Aliware的第三方包只发布在EDAS的私服中,所以需要在Maven中配置EDAS的私服地址。本地开发调试时,需要启动轻量级配置注册中心。轻量级配置及注册中心包含了服务发现和配置管理功能。

在Maven中配置EDAS的私服地址

<?xml version="1.0" encoding="UTF-8"?>

<!--
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.
-->

<!--
 | This is the configuration file for Maven. It can be specified at two levels:
 |
 |  1. User Level. This settings.xml file provides configuration for a single user,
 |                 and is normally provided in ${user.home}/.m2/settings.xml.
 |
 |                 NOTE: This location can be overridden with the CLI option:
 |
 |                 -s /path/to/user/settings.xml
 |
 |  2. Global Level. This settings.xml file provides configuration for all Maven
 |                 users on a machine (assuming they're all using the same Maven
 |                 installation). It's normally provided in
 |                 ${maven.conf}/settings.xml.
 |
 |                 NOTE: This location can be overridden with the CLI option:
 |
 |                 -gs /path/to/global/settings.xml
 |
 | The sections in this sample file are intended to give you a running start at
 | getting the most out of your Maven installation. Where appropriate, the default
 | values (values used when the setting is not specified) are provided.
 |
 |-->
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
  <!-- localRepository
   | The path to the local repository maven will use to store artifacts.
   |
   | Default: ${user.home}/.m2/repository
  <localRepository>/path/to/local/repo</localRepository>
  -->
  <localRepository>/root/.m2/repository</localRepository>

  <!-- interactiveMode
   | This will determine whether maven prompts you when it needs input. If set to false,
   | maven will use a sensible default value, perhaps based on some other setting, for
   | the parameter in question.
   |
   | Default: true
  <interactiveMode>true</interactiveMode>
  -->

  <!-- offline
   | Determines whether maven should attempt to connect to the network when executing a build.
   | This will have an effect on artifact downloads, artifact deployment, and others.
   |
   | Default: false
  <offline>false</offline>
  -->

  <!-- pluginGroups
   | This is a list of additional group identifiers that will be searched when resolving plugins by their prefix, i.e.
   | when invoking a command line like "mvn prefix:goal". Maven will automatically add the group identifiers
   | "org.apache.maven.plugins" and "org.codehaus.mojo" if these are not already contained in the list.
   |-->
  <pluginGroups>
    <!-- pluginGroup
     | Specifies a further group identifier to use for plugin lookup.
    <pluginGroup>com.your.plugins</pluginGroup>
    -->
  </pluginGroups>

  <!-- proxies
   | This is a list of proxies which can be used on this machine to connect to the network.
   | Unless otherwise specified (by system property or command-line switch), the first proxy
   | specification in this list marked as active will be used.
   |-->
  <proxies>
    <!-- proxy
     | Specification for one proxy, to be used in connecting to the network.
     |
    <proxy>
      <id>optional</id>
      <active>true</active>
      <protocol>http</protocol>
      <username>proxyuser</username>
      <password>proxypass</password>
      <host>proxy.host.net</host>
      <port>80</port>
      <nonProxyHosts>local.net|some.host.com</nonProxyHosts>
    </proxy>
    -->
  </proxies>

  <!-- servers
   | This is a list of authentication profiles, keyed by the server-id used within the system.
   | Authentication profiles can be used whenever maven must make a connection to a remote server.
   |-->
  <servers>
    <!-- server
     | Specifies the authentication information to use when connecting to a particular server, identified by
     | a unique name within the system (referred to by the 'id' attribute below).
     |
     | NOTE: You should either specify username/password OR privateKey/passphrase, since these pairings are
     |       used together.
     |
    <server>
      <id>deploymentRepo</id>
      <username>repouser</username>
      <password>repopwd</password>
    </server>
    -->

    <!-- Another sample, using keys to authenticate.
    <server>
      <id>siteServer</id>
      <privateKey>/path/to/private/key</privateKey>
      <passphrase>optional; leave empty if not used.</passphrase>
    </server>
    -->
  </servers>

  <!-- mirrors
   | This is a list of mirrors to be used in downloading artifacts from remote repositories.
   |
   | It works like this: a POM may declare a repository to use in resolving certain artifacts.
   | However, this repository may have problems with heavy traffic at times, so people have mirrored
   | it to several places.
   |
   | That repository definition will have a unique id, so we can create a mirror reference for that
   | repository, to be used as an alternate download site. The mirror site will be the preferred
   | server for that repository.
   |-->
  <mirrors>
  	<!-- 阿里云仓库 -->
  	<mirror>
  		<id>alimaven</id>
  		<mirrorOf>central</mirrorOf>
  		<name>aliyun maven</name>
  		<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
  	</mirror>
  
  	<mirror>
        <id>mirrorId</id>
        <mirrorOf>repositoryId</mirrorOf>
        <name>Human Readable Name for this Mirror.</name>
        <url>http://my.repository.com/repo/path</url>
      </mirror>
  </mirrors>

  <!-- profiles
   | This is a list of profiles which can be activated in a variety of ways, and which can modify
   | the build process. Profiles provided in the settings.xml are intended to provide local machine-
   | specific paths and repository locations which allow the build to work in the local environment.
   |
   | For example, if you have an integration testing plugin - like cactus - that needs to know where
   | your Tomcat instance is installed, you can provide a variable here such that the variable is
   | dereferenced during the build process to configure the cactus plugin.
   |
   | As noted above, profiles can be activated in a variety of ways. One way - the activeProfiles
   | section of this document (settings.xml) - will be discussed later. Another way essentially
   | relies on the detection of a system property, either matching a particular value for the property,
   | or merely testing its existence. Profiles can also be activated by JDK version prefix, where a
   | value of '1.4' might activate a profile when the build is executed on a JDK version of '1.4.2_07'.
   | Finally, the list of active profiles can be specified directly from the command line.
   |
   | NOTE: For profiles defined in the settings.xml, you are restricted to specifying only artifact
   |       repositories, plugin repositories, and free-form properties to be used as configuration
   |       variables for plugins in the POM.
   |
   |-->
   <profiles>
      <profile>
          <id>nexus</id>
          <repositories>
              <repository>
                  <id>central</id>
                  <url>http://repo1.maven.org/maven2</url>
                  <releases>
                      <enabled>true</enabled>
                  </releases>
                  <snapshots>
                      <enabled>true</enabled>
                  </snapshots>
              </repository>
          </repositories>
          <pluginRepositories>
              <pluginRepository>
                  <id>central</id>
                  <url>http://repo1.maven.org/maven2</url>
                  <releases>
                      <enabled>true</enabled>
                  </releases>
                  <snapshots>
                      <enabled>true</enabled>
                  </snapshots>
              </pluginRepository>
          </pluginRepositories>
      </profile>
      <profile>
          <id>edas.oss.repo</id>
          <repositories>
              <repository>
                  <id>edas-oss-central</id>
                  <name>taobao mirror central</name>
                  <url>http://edas-public.oss-cn-hangzhou.aliyuncs.com/repository</url>
                  <snapshots>
                      <enabled>true</enabled>
                  </snapshots>
                  <releases>
                      <enabled>true</enabled>
                  </releases>
              </repository>
              </repositories>
          <pluginRepositories>
              <pluginRepository>
                  <id>edas-oss-plugin-central</id>
                  <url>http://edas-public.oss-cn-hangzhou.aliyuncs.com/repository</url>
                  <snapshots>
                      <enabled>true</enabled>
                  </snapshots>
                  <releases>
                      <enabled>true</enabled>
                  </releases>
              </pluginRepository>
          </pluginRepositories>
      </profile>
    </profiles>
    <activeProfiles>
        <activeProfile>nexus</activeProfile>
        <activeProfile>edas.oss.repo</activeProfile>
    </activeProfiles>

</settings>

测试Maven中配置EDAS的私服地址

在命令行执行命令mvn help:effective-settings,验证配置是否成功。无报错,表明 setting.xml 文件格式没问题。profiles 中包含 edas.oss.repo 这个 profile,表明私服已经配置到 profiles 中。在 activeProfiles 中 包含 edas.oss.repo 属性,表明 edas.oss.repo 私服已激活。说明:如果在命令行执行 Maven 打包命令无问题,IDE 仍无法下载依赖,请关闭 IDE 重新打开试试,或自行查找 IDE 配置 Maven 的相关资料。

mvn help:effective-settings


[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  4.080 s
[INFO] Finished at: 2019-03-05T15:07:23+08:00
[INFO] ------------------------------------------------------------------------

在命令行执行如下命令 mvn help:effective-settings 。可能会报错:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-help-
plugin:3.1.1:effective-settings (default-cli) on project standalone-pom: 
Execution default-cli of goal org.apache.maven.plugins:maven-help-
plugin:3.1.1:effective-settings failed: Plugin org.apache.maven.plugins:maven-
help-plugin:3.1.1 or one of its dependencies could not be resolved: Could not 
find artifact org.sonatype.aether:aether-impl:jar:1.7 in edas-oss-plugin-central 
(http://edas-public.oss-cn-hangzhou.aliyuncs.com/repository) -> [Help 1]

IDEA中配置的maven环境

4.2源码样例

4.2.1 源码下载地址

SpringPrinciple: SpringPrinciple

或者下载源码:https://github.com/aliyun/alibabacloud-microservice-demo/tree/master/microservice-doc-demo/hsf-pandora-boot?spm=a2c4g.11186623.0.0.6beb7062jEQ0Ew

4.3 运行与测试

4.3.1 项目结构说明

hsf-pandora-boot-provider的Maven工程

<properties>
      <java.version>1.8</java.version>
      <spring-boot.version>2.1.6.RELEASE</spring-boot.version>
      <pandora-boot.version>2019-06-stable</pandora-boot.version>
  </properties>

  <dependencies>
      <dependency>
          <groupId>com.alibaba.boot</groupId>
          <artifactId>pandora-hsf-spring-boot-starter</artifactId>
      </dependency>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
  </dependencies>

  <dependencyManagement>
      <dependencies>
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-dependencies</artifactId>
              <version>${spring-boot.version}</version>
              <type>pom</type>
              <scope>import</scope>
          </dependency>
          <dependency>
              <groupId>com.taobao.pandora</groupId>
              <artifactId>pandora-boot-starter-bom</artifactId>
              <version>${pandora-boot.version}</version>
              <type>pom</type>
              <scope>import</scope>
          </dependency>
      </dependencies>
  </dependencyManagement>

  <build>
      <plugins>
          <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-compiler-plugin</artifactId>
              <version>3.7.0</version>
              <configuration>
                  <source>1.8</source>
                  <target>1.8</target>
              </configuration>
          </plugin>
          <plugin>
              <groupId>com.taobao.pandora</groupId>
              <artifactId>pandora-boot-maven-plugin</artifactId>
              <version>2.1.11.8</version>
              <executions>
                  <execution>
                      <phase>package</phase>
                      <goals>
                          <goal>repackage</goal>
                      </goals>
                  </execution>
              </executions>
          </plugin>
      </plugins>
  </build>

虽然HSF服务框架并不依赖于Web环境,但是在应用的生命周期过程中需要使用到Web相关的特性,所以需要添加spring-boot-starter-web的依赖。

pandora-hsf-spring-boot-starter实现了HSF配置的自动装配。pandora-boot-maven-plugin是Pandora Boot提供的Maven打包插件,可以将Pandora Boot HSF工程编译为可执行的FatJar,并在EDAS Container中部署运行。

dependencyManagement中包含了spring-boot-dependenciespandora-boot-starter-bom两个依赖,分别负责Spring Boot和Pandora Boot相关依赖的版本管理,设置之后,您的工程无需将parent设置为spring-boot-starter-parent

定义服务接口,创建一个接口类com.alibaba.edas.HelloService

HSF服务框架基于接口进行服务通信,当接口定义好之后,生产者将通过该接口实现具体的服务并发布,消费者也是基于此接口去订阅和消费服务。

  public interface HelloService {
      String echo(String string);
  }

接口com.alibaba.edas.HelloService提供了echo方法。

添加服务提供者的具体实现类EchoServiceImpl,并通过注解方式发布服务。

  @HSFProvider(serviceInterface = HelloService.class, serviceVersion = "1.0.0")
  public class HelloServiceImpl implements HelloService {
      @Override
      public String echo(String string) {
          return string;
      }
  }

在HSF应用中,接口名和服务版本才能唯一确定一个服务,所以在注解HSFProvider中的需要添加接口名com.alibaba.edas.HelloService和服务版本1.0.0

说明

  • 注解中的配置拥有高优先级。
  • 如果在注解中没有配置,服务发布时会优先在resources/application.properties文件中查找这些属性的全局配置。
  • 如果注解和resources/application.properties文件中都没有配置,则会使用注解中的默认值。
  spring.application.name=hsf-pandora-boot-provider
  server.port=8081

  spring.hsf.version=1.0.0
  spring.hsf.timeout=3000

说明 建议将服务版本(spring.hsf.version)和服务超时(spring.hsf.timeout)都统一配置在application.properties中。

添加服务启动的main函数入口

 @SpringBootApplication
  public class HSFProviderApplication {

      public static void main(String[] args) {
          // 启动Pandora Boot用于加载Pandora容器。PandoraBootstrap.run(args);
          SpringApplication.run(HSFProviderApplication.class, args);
          // 标记服务启动完成,并设置线程wait。防止业务代码运行完毕退出后,导致容器退出。PandoraBootstrap.markStartupAndWait();
      }
  }
服务提供者属性列表
属性是否必配描述类型默认值
serviceInterface服务对外提供的接口Classjava.lang.Object
serviceVersion服务的版本号String1.0.0.DAILY
serviceGroup服务的组名StringHSF
clientTimeout该配置对接口中的所有方法生效,但是如果客户端通过methodSpecials属性对某方法配置了超时时间,则该方法的超时时间以客户端配置为准。其他方法不受影响,还是以服务端配置为准(单位ms)int-1
corePoolSize单独针对这个服务设置最小活跃线程数,从公用线程池中划分出来int0
maxPoolSize单独针对这个服务设置最大活跃线程数,从公用线程池中划分出来int0
delayedPublish是否延迟发布booleanfalse
includeFilters用户可选的自定义过滤器String[]
enableTXC是否开启分布式事务GTSbooleanfalse
serializeType服务接口序列化类型,hessian或者javaStringhessian
supportAsynCall是否支持异步调用Stringfalse
服务创建及发布限制
名称示例限制大小是否可调整
{服务名}:{版本号}com.alibaba.edas.testcase.api.TestCase:1.0.0最大192字节
组名aliware最大32字节
一个Pandora应用实例发布的服务数N/A最大800个是,可在左侧导航栏单击基本信息在基本信息页签内的应用设置区域内,单击JMV参数右侧的编辑,然后在弹出的应用设置对话框中选择自定义 > 自定义参数,在输入框中添加-DCC.pubCountMax=1200属性参数(该参数值可根据应用实际发布的服务数调整)

hsf-pandora-boot-consumerr的Maven工程

  <properties>
      <java.version>1.8</java.version>
      <spring-boot.version>2.1.6.RELEASE</spring-boot.version>
      <pandora-boot.version>2019-06-stable</pandora-boot.version>
  </properties>

  <dependencies>
      <dependency>
          <groupId>com.alibaba.boot</groupId>
          <artifactId>pandora-hsf-spring-boot-starter</artifactId>
      </dependency>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
  </dependencies>

  <dependencyManagement>
      <dependencies>
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-dependencies</artifactId>
              <version>${spring-boot.version}</version>
              <type>pom</type>
              <scope>import</scope>
          </dependency>
          <dependency>
              <groupId>com.taobao.pandora</groupId>
              <artifactId>pandora-boot-starter-bom</artifactId>
              <version>${pandora-boot.version}</version>
              <type>pom</type>
              <scope>import</scope>
          </dependency>
      </dependencies>
  </dependencyManagement>

  <build>
      <plugins>
          <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-compiler-plugin</artifactId>
              <version>3.7.0</version>
              <configuration>
                  <source>1.8</source>
                  <target>1.8</target>
              </configuration>
          </plugin>
          <plugin>
              <groupId>com.taobao.pandora</groupId>
              <artifactId>pandora-boot-maven-plugin</artifactId>
              <version>2.1.11.8</version>
              <executions>
                  <execution>
                      <phase>package</phase>
                      <goals>
                          <goal>repackage</goal>
                      </goals>
                  </execution>
              </executions>
          </plugin>
      </plugins>
  </build>

将服务提供者所发布的API服务接口(包括包名)拷贝到本地,如com.alibaba.edas.HelloService。

  public interface HelloService {
      String echo(String string);
  }

通过注解的方式将服务消费者的实例注入到Spring的Context中。

 @Configuration
  public class HsfConfig {

      @HSFConsumer(clientTimeout = 3000, serviceVersion = "1.0.0")
      private HelloService helloService;

  }

说明HsfConfig类里配置一次@HSFConsumer,然后在多处通过@Autowired注入使用。通常一个@HSFConsumer需要在多个地方使用,但并不需要在每次使用的地方都用@HSFConsumer来标记。只需要写一个统一的HsfConfig类,然后在其它需要使用的地方,直接通过@Autowired注入即可。

为了便于测试,使用SimpleController来暴露一个/hsf-echo/*的HTTP接口,/hsf-echo/*接口内部实现调用了HSF服务提供者。

  @RestController
  public class SimpleController {

      @Autowired
      private HelloService helloService;

      @RequestMapping(value = "/hsf-echo/{str}", method = RequestMethod.GET)
      public String echo(@PathVariable String str) {
          return helloService.echo(str);
      }
  }

在resources目录下的application.properties文件中配置应用名与监听端口号

  spring.application.name=hsf-pandora-boot-consumer
  server.port=8080

  spring.hsf.version=1.0.0
  spring.hsf.timeout=1000

添加服务启动的main函数入口

  @SpringBootApplication
  public class HSFConsumerApplication {

      public static void main(String[] args) {
          PandoraBootstrap.run(args);
          SpringApplication.run(HSFConsumerApplication.class, args);
          PandoraBootstrap.markStartupAndWait();
      }
  }
服务消费者属性列表
属性是否必配描述类型默认值
serviceGroup服务的组名StringHSF
serviceVersion服务的版本号String1.0.0.DAILY
clientTimeout客户端统一设置接口中所有方法的超时时间(单位ms)int-1
generic是否支持泛化调用booleanfalse
addressWaitTime同步等待服务注册中心( ConfigServer )推送服务提供者地址的时间(单位ms)int3000
proxyStyle代理方式(JDK或Javassist)Stringjdk
futureMethods设置调用此服务时需要采用异步调用的方法名列表以及异步调用的方式,默认为空,即所有方法都采用同步调用String[]
consistent负载均衡是否使用一致性哈希String
methodSpecials配置方法级的超时时间、重试次数、方法名称com.alibaba.boot.hsf.annotation.HSFConsumer.ConsumerMethodSpecial[]
服务提供者和消费者全局配置参数列表
属性是否必配描述类型默认值
spring.hsf.version服务的全局版本号,还可以使用spring.hsf.versions.<完整的服务接口名>=<单独为该服务接口设置的版本号,String类型>,例如spring.hsf.versions.com.aliware.edas.EchoService="1.0.0"为具体某个服务设置版本号。String1.0.0.DAILY
spring.hsf.group服务的全局组名,还可以使用spring.hsf.groups.<完整的服务接口名>=<单独为该服务接口设置的组名,String类型>为具体某个服务设置组名。StringHSF
spring.hsf.timeout服务的全局超时时间,还可以使用spring.hsf.timeouts.<完整的服务接口名>=<超时时间,String类型>为具体某个服务设置超时时间。Integer
spring.hsf.max-wait-address-time同步等待服务注册中心( ConfigServer )推送服务提供者地址的全局时间(单位ms ),还可以使用spring.hsf.max-wait-address-times.<完整的服务接口名>=<等待时间,String类型>为具体某个服务设置的等待服务注册中心(ConfigServer)推送服务提供者地址的时间。Integer3000
spring.hsf.delay-publish服务延迟发布的全局开关,”true”or“false”,还可以使用spring.hsf.delay-publishes.<完整的服务接口名>=<是否延迟发布,String类型>为具体某个服务设置是否延迟。String
spring.hsf.core-pool-size服务的全局最小活跃线程数,还可以使用spring.hsf.core-pool-sizes.<完整的服务接口名>=<最小活跃线程数,String类型>单独为某服务设置最小活跃线程数。int
spring.hsf.max-pool-size服务的全局最大活跃线程数,还可以使用spring.hsf.max-pool-sizes.<完整的服务接口名>=<最大活跃线程数,String类型>单独为某服务设置最大活跃线程数。int
spring.hsf.serialize-type服务的全局序列化类型,Hessian或者Java,还可以使用spring.hsf.serialize-types.<完整的服务接口名>=<序列化类型>单独为某服务设置序列化类型。String

4.3.2 本地开发测试

配置轻量级配置及注册中心。本地开发调试时,需要使用轻量级配置及注册中心,轻量级配置及注册中心包含了服务注册发现服务端的轻量版。

启动应用。

  • 在IDE中启动:通过VM options配置启动参数-Djmenv.tbsite.net={$IP},通过main方法直接启动。其中{$IP}为轻量配置中心的IP地址。例如本机启动轻量配置中心,则{$IP}127.0.0.1
  • 您也可以不配置JVM的参数,而是直接通过修改hosts文件将jmenv.tbsite.net绑定为轻量配置中心的IP。

通过FatJar启动

增加taobao-hsf.sar依赖,这样会下载到我们需要的依赖:/.m2/com/taobao/pandora/taobao-hsf.sar/2019-06-stable/taobao-hsf.sar-2019-06-stable.jar,在后面的启动参数中依赖它。

<dependency>
    <groupId>com.taobao.pandora</groupId>
    <artifactId>taobao-hsf.sar</artifactId>
    <version>2019-06-stable</version>
</dependency>

使用Maven将Pandora Boot工程打包成FatJar, 需要在pom.xml中添加如下插件。为避免与其他打包插件发生冲突,请勿在build的plugin中添加其他FatJar插件。

<plugin>
    <groupId>com.taobao.pandora</groupId>
    <artifactId>pandora-boot-maven-plugin</artifactId>
    <version>2.1.11.8</version>
    <executions>
       <execution>
       <phase>package</phase>
       <goals>
            <goal>repackage</goal>
       </goals>
       </execution>
    </executions>
</plugin>

添加完插件后,在工程的主目录下,执行Maven命令mvn clean package进行打包,即可在Target目录下找到打包好的FatJar文件。

通过Java命令启动应用。

java -Djmenv.tbsite.net=127.0.0.1 -Dpandora.location=${M2_HOME}/.m2/repository/com/taobao/pandora/taobao-hsf.sar/2019-06-stable/taobao-hsf.sar-2019-06-stable.jar -jar hsf-pandora-boot-provider-1.0.jar

说明 -Dpandora.location指定的路径必须是全路径,使用命令行启动时,必须显示指定taobao-hsf.sar的位置。访问consumer所在机器的地址,可以触发consumer远程调用provider。

curl localhost:8080/hsf-echo/helloworld

helloworld

4.3.3 单元测试

Pandora Boot的单元测试可以通过PandoraBootRunner启动,并与SpringJUnit4ClassRunner无缝集成。在Maven中添加Pandora Boot和Spring Boot测试必要的依赖。

<dependency>
   <groupId>com.taobao.pandora</groupId>
   <artifactId>pandora-boot-test</artifactId>
   <scope>test</scope>
</dependency>
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
</dependency>
@RunWith(PandoraBootRunner.class)
  @DelegateTo(SpringJUnit4ClassRunner.class)
  // 加载测试需要的类,一定要加入Spring Boot的启动类,其次需要加入本类。
  @SpringBootTest(classes = {HSFProviderApplication.class, HelloServiceTest.class })
  @Component
  public class HelloServiceTest {

      /**
       * 当使用 @HSFConsumer时,一定要在 @SpringBootTest类加载中,加载本类,通过本类来注入对象,否则当做泛化时,会出现类转换异常。
       */
      @HSFConsumer(generic = true)
      HelloService helloService;

      //普通的调用。
      @Test
      public void testInvoke() {
          TestCase.assertEquals("hello world", helloService.echo("hello world"));
      }
      //泛化调用。
      @Test
      public void testGenericInvoke() {
          GenericService service = (GenericService) helloService;
          Object result = service.$invoke("echo", new String[] {"java.lang.String"}, new Object[] {"hello world"});
          TestCase.assertEquals("hello world", result);
      }
      //返回值Mock。
      @Test
      public void testMock() {
          HelloService mock = Mockito.mock(HelloService.class, AdditionalAnswers.delegatesTo(helloService));
          Mockito.when(mock.echo("")).thenReturn("beta");
          TestCase.assertEquals("beta", mock.echo(""));
      }
  }

博文参考

启动轻量级配置及注册中心 - 企业级分布式应用服务 EDAS - 阿里云

开发HSF应用(Pandora Boot) - 企业级分布式应用服务 EDAS - 阿里云

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐