You can use Pandora Boot to develop High-speed Service Framework (HSF) applications and implement service registration and discovery, asynchronous calls, and unit testing. A WAR package is required when you deploy an HSF application in Ali-Tomcat, whereas a JAR package is required when Pandora Boot is used. You can build the HSF application into a FatJar package, which is more consistent with the microservices architecture. This method does not depend on Ali-Tomcat and makes application deployment more flexible. Pandora Boot is an enhancement of Spring Boot.
Prerequisites
Before you develop an application, make sure that the following operations are complete:
Service registration and discovery
This section describes how to develop applications by using Pandora Boot and implement service registration and discovery. The applications include a service provider and a service consumer.
Do not call HSF remote services when you start an application. Otherwise, the application fails to be started.
Download the demo source code. For more information, see Demo source code.
Clone the whole project from GitHub and find the demo project that is used in this topic in the microservice-doc-demo/hsf-pandora-boot directory.
Create a service provider.
Create a Maven project named hsf-pandora-boot-provider.
Add the required dependencies to the pom.xml file.
<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 is independent of the web environment. However, you must add the
spring-boot-starter-web
dependency because web-related features are required in the application lifecycle.pandora-hsf-spring-boot-starter
implements automatic installation and configuration of HSF.pandora-boot-maven-plugin
is a Maven packaging plug-in that is provided by Pandora Boot. This plug-in can compile a Pandora Boot HSF project as an executable FatJar package and then deploy and run the package in Enterprise Distributed Application Service (EDAS) Container.dependencyManagement
consists of thespring-boot-dependencies
andpandora-boot-starter-bom
dependencies. You can use the dependencies to separately manage the versions of related Spring Boot and Pandora Boot dependencies without the need to set parent tospring-boot-starter-parent
for your project.Define a service interface, and create an interface class named
com.alibaba.edas.HelloService
.HSF implements service communication based on interfaces. After an interface is defined, it is used by producers to implement and publish services and by consumers to subscribe to and consume services.
public interface HelloService { String echo(String string); }
The com.alibaba.edas.HelloService interface provides the echo method.
Add the EchoServiceImpl implementation class of the service provider, and publish the service by using annotations.
@HSFProvider(serviceInterface = HelloService.class, serviceVersion = "1.0.0") public class HelloServiceImpl implements HelloService { @Override public String echo(String string) { return string; } }
In HSF applications, a service is uniquely identified by the interface name and service version. Therefore, you must add the com.alibaba.edas.HelloService interface name and the
1.0.0
service version to the HSFProvider annotation.NoteThe configurations in the HSFProvider annotation have a higher priority.
If properties are not configured in the HSFProvider annotation, the global configurations of these properties in the resources/application.properties file are searched first when the service is published.
If properties are not configured in the HSFProvider annotation or the resources/application.properties file, the default values in the annotation are used.
Configure the application name and the listener port number in the application.properties file in the resources directory.
spring.application.name=hsf-pandora-boot-provider server.port=8081 spring.hsf.version=1.0.0 spring.hsf.timeout=3000
NoteWe recommend that you configure both the service version (
spring.hsf.version
) and service timeout period (spring.hsf.timeout
) in the application.properties file.Add the main function handler for starting the service.
@SpringBootApplication public class HSFProviderApplication { public static void main(String[] args) { // Start Pandora Boot to load the Pandora container. PandoraBootstrap.run(args); SpringApplication.run(HSFProviderApplication.class, args); // Mark the service as started and specify the thread wait time. This prevents the container from exiting after you run the service code and exit. PandoraBootstrap.markStartupAndWait(); } }
Table 1: Properties of the service provider Property
Required
Description
Type
Default value
serviceInterface
Yes
The interface that provides services.
Class
java.lang.Object
serviceVersion
No
The version of the service.
String
1.0.0.DAILY
serviceGroup
No
The group name of the service.
String
HSF
clientTimeout
No
This property applies to all methods in the interface. However, if a timeout period is configured for a method of the consumer by using the methodSpecials property, the configured timeout period takes precedence over this property value for this method. Other methods still use the timeout period configured for the provider. Unit: milliseconds.
int
-1
corePoolSize
No
The minimum number of active threads that are allocated from the public thread pool for the service.
int
0
maxPoolSize
No
The maximum number of active threads that are allocated from the public thread pool for the service.
int
0
delayedPublish
No
Specifies whether to delay the service publishing.
boolean
false
includeFilters
No
The custom filters that you can use.
String[]
Null
enableTXC
No
Specifies whether to enable Global Transaction Service (GTS) for distributed transactions.
boolean
false
serializeType
No
The serialization type of the service interface. Valid values: hessian and java.
String
hessian
supportAsynCall
No
Specifies whether to support asynchronous calls.
String
false
Table 2: Limits on service creation and publishing Item
Example
Upper limit
Adjustable
{Service name}:{Version number}
com.alibaba.edas.testcase.api.TestCase:1.0.0
192 bytes
No
Group name
aliware
32 bytes
No
Number of services published for a Pandora application instance
N/A
800
Yes. In the left-side navigation pane of the application details page, click Basic Information. In the Application Settings section of the Basic Information tab, click Edit on the right side of JVM Parameters. In the Application Settings dialog box, click Custom and enter
-DCC.pubCountMax=1200
in the Custom Parameters field. You can change the value of DCC.pubCountMax based on the number of services published for the application.
Create a service consumer.
In this example, a service consumer is created to call the service provider by using the interfaces provided by HSFConsumer.
Create a Maven project named hsf-pandora-boot-consumer.
Add the required dependencies to the pom.xml file.
NoteThe Maven dependencies for the consumer and provider are the same.
<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>
Copy the service interface that is published by the service provider, such as the com.alibaba.edas.HelloService interface, to the local environment. The package name is also copied.
public interface HelloService { String echo(String string); }
Use annotations to inject the service consumer instance to the Spring context.
@Configuration public class HsfConfig { @HSFConsumer(clientTimeout = 3000, serviceVersion = "1.0.0") private HelloService helloService; }
NoteConfigure an
@HSFConsumer
annotation once in theHsfConfig
class, and then inject and use the annotation in multiple places by using@Autowired
. In most cases, an@HSFConsumer
annotation is used in multiple places, but you do not need to use@HSFConsumer
to mark each place where the annotation is used. You need to only write anHsfConfig
class and inject it by using@Autowired
.To facilitate testing, you can use SimpleController to expose an /hsf-echo/* HTTP interface. The /hsf-echo/* interface provides built-in capabilities to call the HSF service provider.
@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); } }
Configure the application name and the listener port number in the application.properties file in the resources directory.
spring.application.name=hsf-pandora-boot-consumer server.port=8080 spring.hsf.version=1.0.0 spring.hsf.timeout=1000
NoteWe recommend that you specify the service version and timeout period in the application.properties file.
Add the main function handler for starting the service.
@SpringBootApplication public class HSFConsumerApplication { public static void main(String[] args) { PandoraBootstrap.run(args); SpringApplication.run(HSFConsumerApplication.class, args); PandoraBootstrap.markStartupAndWait(); } }
Table 3: Properties of the service consumer Property
Required
Description
Type
Default value
serviceGroup
No
The group name of the service.
String
HSF
serviceVersion
No
The version of the service.
String
1.0.0.DAILY
clientTimeout
No
The timeout period for all methods in the interface of the consumer. Unit: milliseconds.
int
-1
generic
No
Specifies whether to support generic calls.
boolean
false
addressWaitTime
No
The time used to wait for the service registry (ConfigServer) to push the service provider address. Unit: milliseconds.
int
3000
proxyStyle
No
The proxy style. Valid values: JDK and Javassist.
String
jdk
futureMethods
No
The names of methods in asynchronous call mode on the service. Default value: Null. A value of Null specifies that all methods are called in synchronous mode.
String[]
Null
consistent
No
Specifies whether to use consistent hashing.
String
Null (Consistent hashing is not used.)
methodSpecials
No
The method-level timeout period and number of retries, and the method name.
com.alibaba.boot.hsf.annotation.HSFConsumer.ConsumerMethodSpecial[]
Null
Table 4: Global properties for the service provider and the service consumer Property
Required
Description
Type
Default value
spring.hsf.version
No
The global version of the service. If you want to use this property as a local property of the service, specify this property in the following format:
spring.hsf.versions.<Complete service interface name>=<Version number separately specified for the service interface, in String format>
. Example:spring.hsf.versions.com.aliware.edas.EchoService="1.0.0"
.String
1.0.0.DAILY
spring.hsf.group
No
The global group name of the service. If you want to use this property as a local property of the service, specify this property in the following format:
spring.hsf.groups.<Complete service interface name>=<Group name separately specified for the service interface, in String format>
.String
HSF
spring.hsf.timeout
No
The global timeout period of the service. If you want to use this property as a local property of the service, specify this property in the following format:
spring.hsf.timeouts.<Complete service interface name>=<Timeout period, in String format>
.Integer
None
spring.hsf.max-wait-address-time
No
The global time used to wait for the service registry (ConfigServer) to push the service provider address. Unit: milliseconds. If you want to use this property as a local property of the service, specify this property in the following format:
spring.hsf.max-wait-address-times.<Complete service interface name>=<Wait time, in String format>
.Integer
3000
spring.hsf.delay-publish
No
The global switch for service publishing delay. Valid values: true and false. If you want to use this property as a local property of the service, specify this property in the following format:
spring.hsf.delay-publishes.<Complete service interface name>=<Whether to delay the service publishing, in String format>
.String
None
spring.hsf.core-pool-size
No
The minimum number of globally active threads for the service. If you want to use this property as a local property of the service, specify this property in the following format:
spring.hsf.core-pool-sizes.<Complete service interface name>=<Minimum number of active threads, in String format>
.int
None
spring.hsf.max-pool-size
No
The maximum number of globally active threads for the service. If you want to use this property as a local property of the service, specify this property in the following format:
spring.hsf.max-pool-sizes.<Complete service interface name>=<Maximum number of active threads, in String format>
.int
None
spring.hsf.serialize-type
No
The global serialization type of the service. Valid values: Hessian and Java. If you want to use this property as a local property of the service, specify this property in the following format:
spring.hsf.serialize-types.<Complete service interface name>=<Serialization type>
.String
None
NoteYou can configure global properties in the application.properties file of Pandora Boot applications.
Local code development and debugging
Configure the lightweight configuration and registry center.
You must use the lightweight configuration and registry center for local code development and debugging, which includes a lightweight service registry. For more information, see Start the lightweight configuration center.
Start the application by using one of the following methods:
Start the application in an integrated development environment (IDE).
To start the application in an IDE, configure the startup parameter -Djmenv.tbsite.net={$IP} by using VM options and start the application by calling the main method. In the startup parameter,
{$IP}
specifies the IP address of the lightweight configuration center. For example, the value of{$IP}
is127.0.0.1
for the lightweight configuration center that is locally started.You can also set
jmenv.tbsite.net
to the IP address of the lightweight configuration center in the hosts file, without setting JVM parameters. For more information, see Start the lightweight configuration center.Start the application by using FatJar.
Add the taobao-hsf.sar dependency to your code to download the ${USER_HOME}/.m2/com/taobao/pandora/taobao-hsf.sar/2019-06-stable/taobao-hsf.sar-2019-06-stable.jar dependency on which the startup parameters in later steps depend.
<dependency> <groupId>com.taobao.pandora</groupId> <artifactId>taobao-hsf.sar</artifactId> <version>2019-06-stable</version> </dependency>
Add the following plug-in to the pom.xml file to build the Pandora Boot project into a FatJar package by using Maven. To prevent conflicts with other packaging plug-ins, do not add configurations of other FatJar plug-ins to the plugin field in build.
<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>
After you add the plug-in, run the
mvn clean package
command in the home directory of the project to build a package. Then, you can find the packaged FatJar file in the Target directory.Start the application by running the following Java command:
java -Djmenv.tbsite.net=127.0.0.1 -Dpandora.location=${USER_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
NoteThe path specified by
-Dpandora.location
must be a full path. When you start the application in the command line, you must explicitly specify the location of taobao-hsf.sar.The value format of
${USER_HOME}
varies based on the type of your OS:macOS/Linux:
/Users/<Current user>
.Windows:
C:\Users\<Current user>
.
Access the address of the instance where the consumer is located for the consumer to remotely call services of the provider.
curl localhost:8080/hsf-echo/helloworld helloworld
Unit testing
The Pandora Boot unit testing can be started by PandoraBootRunner and is seamlessly integrated with SpringJUnit4ClassRunner.
The following example demonstrates how to perform unit testing for a service provider.
Add the dependencies required for the Pandora Boot and Spring Boot unit testing in Maven.
<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>
Compile the test code.
@RunWith(PandoraBootRunner.class) @DelegateTo(SpringJUnit4ClassRunner.class) // Add both the Spring Boot startup class and service test class required for unit testing. @SpringBootTest(classes = {HSFProviderApplication.class, HelloServiceTest.class }) @Component public class HelloServiceTest { /** * If you use @HSFConsumer, you must add the service class to @SpringBootTest and use the class to inject objects to prevent abnormal class conversion during generic calls. */ @HSFConsumer(generic = true) HelloService helloService; // Perform a common call. @Test public void testInvoke() { TestCase.assertEquals("hello world", helloService.echo("hello world")); } // Perform a generic call. @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); } // Return the value of 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("")); } }