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 package the HSF application into a FatJar package, which is more consistent with the microservice architecture. This method does not depend on Ali-Tomcat and makes application deployment more flexible. Pandora Boot is an enhancement of Spring Boot.
Prerequisites
Service registration and discovery
Download the demo source code. For more information, see Demo source code.
Clone the project from GitHub and find the demo project 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 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 HSF is independent of the web environment, web-related features are required in the application lifecycle. Therefore, the
spring-boot-starter-web
dependency must be added.pandora-hsf-spring-boot-starter
implements automatic installation and configuration of HSF.pandora-boot-maven-plugin
is a Maven packaging plug-in provided by Pandora Boot. It can compile a Pandora Boot HSF project as an executable FatJar package, which can be deployed and run in Enterprise Distributed Application Service (EDAS) Container.dependencyManagement
includes thespring-boot-dependencies
andpandora-boot-starter-bom
dependencies, which manage related versions of Spring Boot and Pandora Boot. You do not 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 enables interface-based service communication. When an interface is defined, producers implement and publish specific services by using this interface, and consumers subscribe to and consume services by using this interface.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.Note- The configuration in the annotation has a higher priority.
- If they are not configured in the HSFProvider annotation, the global configurations of these properties are searched first in the resources/application.properties file when the service is published.
- If they 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
Note We recommend that you configure both the service version (spring.hsf.version
) and service timeout (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); // Indicate that the service is started, and set the thread wait time. This prevents the container from exiting after a user runs the service code and exits. PandoraBootstrap.markStartupAndWait(); } }
Table 1. Service provider properties 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 the consumer sets a timeout period for a method by using the methodSpecials property, the set timeout period takes precedence over this property value for this method. Other methods still use the timeout period configured on the provider. Unit: milliseconds. Integer -1 corePoolSize No The minimum number of active threads that are allocated from the public thread pool for this service. Integer 0 maxPoolSize No The maximum number of active threads that are allocated from the public thread pool for this service. Integer 0 delayedPublish No Specifies whether to delay the service publishing. boolean false includeFilters No The custom filters for you to choose. 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 Parameter Example Maximum size 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 by a Pandora application N/A 800 Yes. In the left-side navigation pane, click Basic Information. On the Basic Information tab, click Edit next to JMV Parameters in the Application Settings section. Then, in the Application Settings dialog box, choose Custom > Custom Parameters. In the Custom Parameters field, enter -DCC.pubCountMax=1200
. You can change the value of the parameter based on the number of published services of the application.
- Create a service consumer. In this example, a service consumer is created to call services by using the interface in HSFConsumer.
- Create a Maven project named hsf-pandora-boot-consumer.
- Add required dependencies to the pom.xml file. Note The 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 com.alibaba.edas.HelloService service interface published by the service provider to the local environment. The
name of the package 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; }
Note Configure@HSFConsumer
once in theHsfConfig
class, and then inject and use it in multiple steps by using@Autowired
. An@HSFConsumer
is used in multiple places, but you do not need to mark each place where it is used with@HSFConsumer
. You need only to write anHsfConfig
class and inject it by using@Autowired
. - To facilitate testing, you can use SimpleController to expose a /hsf-echo/* HTTP interface. The /hsf-echo/* interface can be used 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
Note We recommend that you set 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. Service consumer properties 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 set by the consumer for all methods in an interface, in milliseconds. Integer -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, in milliseconds. Integer 3000 proxyStyle No The proxy style. Valid values: JDK and Javassist. String jdk futureMethods No The list of methods in asynchronous call mode on the service. Default value: Null. This value indicates that all methods are called in asynchronous mode. String[] Empty consistent No Specifies whether to use consistent hashing. String Empty methodSpecials No The method-level timeout period, number of retries, and method name. com.alibaba.boot.hsf.annotation.HSFConsumer.ConsumerMethodSpecial[] Empty Table 4. Global properties for service providers and consumers Property Required Description Type Default value spring.hsf.version No The global version of the service. You can also use spring.hsf.versions.<Complete service interface name>=<Version number set only for the service interface, in String format>
, such asspring.hsf.versions.com.aliware.edas.EchoService="1.0.0"
, to specify the version of a service.String 1.0.0.DAILY spring.hsf.group No The global group name of the service. You can also use spring.hsf.groups.<Complete service interface name>=<Group name set only for the service interface, in String format>
to specify the group name for a service.String HSF spring.hsf.timeout No The global timeout period of the service. You can also use spring.hsf.timeouts.<Complete service interface name>=<Timeout period, in String format>
to specify the timeout period for a service.Integer No default value spring.hsf.max-wait-address-time No The global time used to wait for the service registry (ConfigServer) to push the service provider address, in milliseconds. You can also use spring.hsf.max-wait-address-times.<Complete service interface name>=<Response time, in String format>
to specify the property.Integer 3000 spring.hsf.delay-publish No The global switch for service publishing delay. Valid values: true and false. You can also use spring.hsf.delay-publishes.<Complete service interface name>=<Whether to delay the service publishing, in String format>
to specify the property.String No default value spring.hsf.core-pool-size No The minimum number of globally active threads for the service. You can also use spring.hsf.core-pool-sizes.<Complete service interface name>=<Minimum number of active threads, in String format>
to specify the property.Integer No default value spring.hsf.max-pool-size No The maximum number of globally active threads for the service. You can also use spring.hsf.max-pool-sizes.<Complete service interface name>=<Maximum number of active threads, in String format>
to specify the property.Integer No default value spring.hsf.serialize-type No The global serialization type of the service. Valid values: Hessian and Java. You can also use spring.hsf.serialize-types.<Complete service interface parameter>=<Serialization type>
to specify the property.String No default value Note Global parameters can be set in the application.properties file of Pandora Boot applications.
Local code development and debugging
- Configure the lightweight configuration and registry center. The lightweight configuration and registry center must be used for local code development and debugging, which includes a lightweight service registry. For more information, see Start the light-weight configuration registry.
- Starts an application.
- Start the application in an integrated development environment (IDE)
To start the application in IDE, configure the startup parameter -Djmenv.tbsite.net={$IP} in VM options and start the application by calling the main method. In the parameter,
{$IP}
indicates 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 light-weight configuration registry. - Start the application by using FatJar
- Add the taobao-hsf.sar dependency /.m2/com/taobao/pandora/taobao-hsf.sar/2019-06-stable/taobao-hsf.sar-2019-06-stable.jar,
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>
- To package the Pandora Boot project into a FatJar package by using Maven, add the
following plug-in to pom.xml. 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 create a package in the target directory. Then, you can find the packaged FatJar file. - Start the application by running the following Java command:
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
Note The path specified by-Dpandora.location
must be a full path, which must specify the location of taobao-hsf.sar when you start the application in the command line.
- Add the taobao-hsf.sar dependency /.m2/com/taobao/pandora/taobao-hsf.sar/2019-06-stable/taobao-hsf.sar-2019-06-stable.jar,
on which the startup parameters in later steps depend.
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
- Start the application in an integrated development environment (IDE)
Unit testing
The Pandora Boot unit testing can be started by PandoraBootRunner and seamlessly integrated with SpringJUnit4ClassRunner.
The following example demonstrates how to perform unit testing for service providers:
- Add 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 are using @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; // Common calls. @Test public void testInvoke() { TestCase.assertEquals("hello world", helloService.echo("hello world")); } // Generic calls. @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); } // The return value 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("")); } }