Use Pandora Boot to develop High-speed Service Framework (HSF) applications. You can implement service registration and discovery, perform asynchronous calls, and run unit tests. Unlike deploying HSF WAR packages with Ali-Tomcat, Pandora Boot deploys JAR packages. You can directly package an HSF application as a FatJar. This approach aligns better with the microservice style and makes application deployment more flexible because it does not require an external Ali-Tomcat. Pandora Boot can be considered an enhancement of Spring Boot.
Prerequisites
Before you develop the application, complete the following tasks:
Service registration and discovery
This topic describes how to use Pandora Boot to develop applications that include a service provider and a service consumer to implement service registration and discovery.
Do not call HSF remote services when you start an application. Otherwise, the application fails to start.
Download the demo source code.
Clone the entire project using Git. You can find the sample project used in this topic in the microservice-doc-demo/hsf-pandora-boot folder.
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>Although the HSF service framework does not depend on a web environment, web-related features are required during the application lifecycle. Therefore, you must add the
spring-boot-starter-webdependency.pandora-hsf-spring-boot-starterimplements automatic configuration for HSF.pandora-boot-maven-pluginis a Maven packaging plugin provided by Pandora Boot. This plugin compiles a Pandora Boot HSF project into an executable FatJar. You can then deploy and run the package in EDAS Container.dependencyManagementcontains thespring-boot-dependenciesandpandora-boot-starter-bomdependencies. These dependencies manage the versions of the Spring Boot and Pandora Boot dependencies. After you add them, you do not need to set the parent of your project tospring-boot-starter-parent.Define a service interface. Create an interface class
com.alibaba.edas.HelloService.The HSF service framework uses interfaces for service communication. A producer implements and publishes a service through a defined interface, and a consumer subscribes to and consumes the service based on the same interface.
public interface HelloService { String echo(String string); }The com.alibaba.edas.HelloService interface provides the echo method.
Add the EchoServiceImpl implementation class for the service provider and publish the service using an annotation.
@HSFProvider(serviceInterface = HelloService.class, serviceVersion = "1.0.0") public class HelloServiceImpl implements HelloService { @Override public String echo(String string) { return string; } }In an HSF application, a service is uniquely identified by its interface name and service version. Therefore, you must add the interface name com.alibaba.edas.HelloService and the service version
1.0.0to the HSFProvider annotation.NoteConfigurations in the annotation have the highest priority.
If a property is not configured in the annotation, the system searches for the global configuration of the property in the resources/application.properties file when the service is published.
If the property is not configured in the annotation or the resources/application.properties file, the default value in the annotation is used.
In the resources directory, configure the application name and listening port in the application.properties file.
spring.application.name=hsf-pandora-boot-provider server.port=8081 spring.hsf.version=1.0.0 spring.hsf.timeout=3000NoteConfigure both the service version (
spring.hsf.version) and service timeout (spring.hsf.timeout) in the application.properties file.Add the main function entry point to start 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 that the service has started and set the thread to wait. This prevents the container from exiting after the business code finishes running. PandoraBootstrap.markStartupAndWait(); } }Table 1. Service provider properties Property
Required
Description
Type
Default value
serviceInterface
Yes
The interface that the service exposes.
Class
java.lang.Object
serviceVersion
No
The version number of the service.
String
1.0.0.DAILY
serviceGroup
No
The group name of the service.
String
HSF
clientTimeout
No
This configuration applies to all methods in the interface. However, if the client configures a timeout for a specific method using the `methodSpecials` property, the client's configuration takes precedence for that method. Other methods are not affected and still use the server-side configuration. Unit: ms.
int
-1
corePoolSize
No
The minimum number of active threads allocated from the shared thread pool specifically for this service.
int
0
maxPoolSize
No
The maximum number of active threads allocated from the shared thread pool specifically for this service.
int
0
delayedPublish
No
Specifies whether to delay publishing the service.
boolean
false
includeFilters
No
Optional custom filters.
String[]
Empty
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. Service creation and publishing limits Name
Example
Size limit
Adjustable
{Service name}:{Version number}
com.alibaba.edas.testcase.api.TestCase:1.0.0
Up to 192 bytes
No
Group name
aliware
Up to 32 bytes
No
Number of services published by a Pandora application instance
N/A
Up to 800
Yes. In the navigation pane on the left, click Basic Information. On the Basic Information tab, in the Application Settings section, click Edit to the right of JVM Parameters. In the Application Settings dialog box that appears, select . In the input box, add the
-DCC.pubCountMax=1200property parameter. You can adjust this value based on the actual number of services your application publishes.
Create a service consumer.
In this example, you will create a service consumer that calls the service provider using the API operations 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 are the same as for the provider.
<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 API service interface published by the service provider, including the package name, to the consumer project, such as com.alibaba.edas.HelloService.
public interface HelloService { String echo(String string); }Inject the service consumer instance into the Spring context using an annotation.
@Configuration public class HsfConfig { @HSFConsumer(clientTimeout = 3000, serviceVersion = "1.0.0") private HelloService helloService; }NoteYou can configure
@HSFConsumeronce in theHsfConfigclass, and then inject it for use in multiple locations with@Autowired. Although the@HSFConsumerannotation is used in multiple locations, you do not need to mark each location with@HSFConsumer. Instead, you can create a unifiedHsfConfigclass and inject it directly with@Autowiredwhere needed.For testing purposes, use SimpleController to expose an /hsf-echo/* HTTP interface. The /hsf-echo/* interface internally calls 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); } }In the resources directory, configure the application name and listening port in the application.properties file.
spring.application.name=hsf-pandora-boot-consumer server.port=8080 spring.hsf.version=1.0.0 spring.hsf.timeout=1000NoteConfigure both the service version and service timeout in the application.properties file.
Add the main function entry point to start the service.
@SpringBootApplication public class HSFConsumerApplication { public static void main(String[] args) { PandoraBootstrap.run(args); SpringApplication.run(HSFConsumerApplication.class, args); PandoraBootstrap.markStartupAndWait(); } }Table 3. Service consumer properties Property
Required
Description
Type
Default value
serviceGroup
No
The group name of the service.
String
HSF
serviceVersion
No
The version number of the service.
String
1.0.0.DAILY
clientTimeout
No
The timeout for all methods in the client interface. Unit: ms.
int
-1
generic
No
Specifies whether to support generalized calls.
boolean
false
addressWaitTime
No
The time to wait for the service registry (ConfigServer) to push the service provider address. Unit: ms.
int
3000
proxyStyle
No
The proxy style. Valid values: `JDK` and `Javassist`.
String
jdk
futureMethods
No
A list of method names that must be called asynchronously when this service is invoked, and the asynchronous invocation method. The default value is empty, which means all methods are called synchronously.
String[]
Empty
consistent
No
Specifies whether to use consistent hashing for load balancing.
String
Empty (An empty value indicates that consistent hashing is not used).
methodSpecials
No
Configures the method-level timeout, number of retries, and method name.
com.alibaba.boot.hsf.annotation.HSFConsumer.ConsumerMethodSpecial[]
Empty
Table 4. Global configuration parameters for the service provider and consumer Property
Required
Description
Type
Default value
spring.hsf.version
No
The global version number for services. You can also use
spring.hsf.versions.<full service interface name>=<version number for this specific interface, String type>to set a version number for a specific service. For example:spring.hsf.versions.com.aliware.edas.EchoService="1.0.0".String
1.0.0.DAILY
spring.hsf.group
No
The global group name for services. You can also use
spring.hsf.groups.<full service interface name>=<group name for this specific interface, String type>to set a group name for a specific service.String
HSF
spring.hsf.timeout
No
The global timeout for services. You can also use
spring.hsf.timeouts.<full service interface name>=<timeout, String type>to set a timeout for a specific service.Integer
None
spring.hsf.max-wait-address-time
No
The global time to wait for the service registry (ConfigServer) to push the service provider address. Unit: ms. You can also use
spring.hsf.max-wait-address-times.<full service interface name>=<wait time, String type>to set the wait time for a specific service.Integer
3000
spring.hsf.delay-publish
No
The global switch for delayed service publishing. Valid values: `true` or `false`. You can also use
spring.hsf.delay-publishes.<full service interface name>=<whether to delay publishing, String type>to set a delay for a specific service.String
None
spring.hsf.core-pool-size
No
The global minimum number of active threads for services. You can also use
spring.hsf.core-pool-sizes.<full service interface name>=<minimum active threads, String type>to set the minimum number of active threads for a specific service.int
None
spring.hsf.max-pool-size
No
The global maximum number of active threads for services. You can also use
spring.hsf.max-pool-sizes.<full service interface name>=<maximum active threads, String type>to set the maximum number of active threads for a specific service.int
None
spring.hsf.serialize-type
No
The global serialization type for services. Valid values: `Hessian` or `Java`. You can also use
spring.hsf.serialize-types.<full service interface name>=<serialization type>to set the serialization type for a specific service.String
None
NoteYou can set global configuration parameters in the application.properties file of a Pandora Boot application.
Local development and debugging
Configure the lightweight configuration and registry center.
For local development and debugging, you must use the lightweight configuration and registry center. This center includes a lightweight version of the service registration and discovery server. For more information, see Start the lightweight configuration and registry center.
Start the application.
Start in an IDE
Configure the
-Djmenv.tbsite.net={$IP}startup parameter in the VM options and start the application from the main method.{$IP}is the IP address of the lightweight configuration center. For example, if you start the lightweight configuration center on your local machine,{$IP}is127.0.0.1.Alternatively, you can modify the hosts file to bind
jmenv.tbsite.netto the IP address of the lightweight configuration center instead of configuring JVM parameters. For more information, see Start the lightweight configuration and registry center.Start using a FatJar
Add the `taobao-hsf.sar` dependency. This step downloads the required dependency to `${USER_HOME}/.m2/repository/com/taobao/pandora/taobao-hsf.sar/2019-06-stable/taobao-hsf.sar-2019-06-stable.jar`, which is required for the startup parameters.
<dependency> <groupId>com.taobao.pandora</groupId> <artifactId>taobao-hsf.sar</artifactId> <version>2019-06-stable</version> </dependency>Use Maven to package the Pandora Boot project as a FatJar. You need to add the following plugin to the pom.xml file. To avoid conflicts with other packaging plugins, do not add other FatJar plugins to the `plugins` section of the 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 plugin, run the
mvn clean packagecommand in the project's home directory to package the project. You can find the packaged FatJar file in the Target directory.Start the application by running a 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.jarNoteThe path specified by
-Dpandora.locationmust be a full path. When you start the application from the command line, you must explicitly specify the location of `taobao-hsf.sar`.Replace the
${USER_HOME}parameter based on your operating system.macOS/Linux:
/Users/<current_user>.Windows:
C:\Users\<current_user>.
Access the address of the machine where the consumer is located. This triggers the consumer to remotely call the provider.
curl localhost:8080/hsf-echo/helloworld helloworld
Unit testing
You can run Pandora Boot unit tests using `PandoraBootRunner`, which is seamlessly integrated with `SpringJUnit4ClassRunner`.
The following example shows how to perform a unit test in the service provider.
In Maven, add the necessary dependencies for Pandora Boot and Spring Boot testing.
<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>You can write the code for the test class.
@RunWith(PandoraBootRunner.class) @DelegateTo(SpringJUnit4ClassRunner.class) // Load the classes required for the test. Be sure to add the Spring Boot startup class and this test class. @SpringBootTest(classes = {HSFProviderApplication.class, HelloServiceTest.class }) @Component public class HelloServiceTest { /** * When you use @HSFConsumer, you must load this class in the @SpringBootTest class loading process and use this class to inject the object. Otherwise, a class conversion exception occurs during generalization. */ @HSFConsumer(generic = true) HelloService helloService; // A regular call. @Test public void testInvoke() { TestCase.assertEquals("hello world", helloService.echo("hello world")); } // A generalized 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); } // Mock the return value. @Test public void testMock() { HelloService mock = Mockito.mock(HelloService.class, AdditionalAnswers.delegatesTo(helloService)); Mockito.when(mock.echo("")).thenReturn("beta"); TestCase.assertEquals("beta", mock.echo("")); } }