Spring cloud HSF 集成 HSF 高级特性

链接地址:https://helpcdn.aliyun.com/document_detail/63868.html

本页目录

  • 单元测试
  • 异步调用

在之前的文档中,HSF 开发已经介绍了如何使用 Spring Cloud 来开发 HSF 应用。

本文将介绍一下 HSF 的一些高级特性在 Spring Cloud 开发方式下的使用方式。目前内容包含 单元测试 和 异步调用 两部分,后续会有更多的介绍。

Demo 源码下载: sc-hsf-provider 、 sc-hsf-consumer。

单元测试

spring-cloud-starter-hsf 的实现依赖于 Pandora Boot,Pandora Boot 的单元测试可以通过 PandoraBootRunner 启动,并与 SpringJUnit4ClassRunner 无缝集成。

我们将演示一下,如何在服务提供者中进行单元测试,供大家参考。

  1. 在 Maven 中添加 spring-boot-starter-test 的依赖。

     
    1. org.springframework.boot
    2. spring-boot-starter-test
  2. 编写测试类的代码。

     
    1. @RunWith(PandoraBootRunner.class)
    2. @DelegateTo(SpringJUnit4ClassRunner.class)
    3. // 加载测试需要的类,一定要加入 Spring Boot 的启动类,其次需要加入本类。
    4. @SpringBootTest(classes = {HSFProviderApplication.class, EchoServiceTest.class })
    5. @Component
    6. public class EchoServiceTest {
    7.  
    8. /**
    9. * 当使用 @HSFConsumer 时,一定要在 @SpringBootTest 类加载中,加载本类,通过本类来注入对象,否则当做泛化时,会出现类转换异常。
    10. */
    11. @HSFConsumer(generic = true)
    12. EchoService echoService;
    13.  
    14. //普通的调用
    15. @Test
    16. public void testInvoke() {
    17. TestCase.assertEquals("hello world", echoService.echo("hello world"));
    18. }
    19. //泛化调用
    20. @Test
    21. public void testGenericInvoke() {
    22. GenericService service = (GenericService) echoService;
    23. Object result = service.$invoke("echo", new String[] {"java.lang.String"}, new Object[] {"hello world"});
    24. TestCase.assertEquals("hello world", result);
    25. }
    26. //返回值 Mock
    27. @Test
    28. public void testMock() {
    29. EchoService mock = Mockito.mock(EchoService.class, AdditionalAnswers.delegatesTo(echoService));
    30. Mockito.when(mock.echo("")).thenReturn("beta");
    31. TestCase.assertEquals("beta", mock.echo(""));
    32. }
    33. }

异步调用

HSF 提供了两种类型的异步调用,Future 和 Callback。

  1. 在演示异步调用之前,我们先发布一个新的服务: com.aliware.edas.async.AsyncEchoService。

     
    1. public interface AsyncEchoService {
    2. String future(String string);
    3. String callback(String string);
    4. }
  2. 服务提供者实现 AsyncEchoService,并通过注解发布。

     
    1. @HSFProvider(serviceInterface = AsyncEchoService.class, serviceVersion = "1.0.0")
    2. public class AsyncEchoServiceImpl implements AsyncEchoService {
    3. @Override
    4. public String future(String string) {
    5. return string;
    6. }
    7.  
    8. @Override
    9. public String callback(String string) {
    10. return string;
    11. }
    12. }

    从这两点中可以看出,服务提供端与普通的发布没有任何区别,同样,之后的配置和应用启动流程也是一致的,详情请参考 HSF 开发中创建服务提供者部分的内容。

    注意:异步调用的逻辑修改都在消费端,服务端无需做任何修改。

Future

  1. 使用 Future 类型的异步调用的消费端,也是通过注解的方式将服务消费者的实例注入到 Spring 的 Context 中,并在 @HSFConsumer 注解的 futureMethods 属性中配置异步调用的方法名。

    这里我们将 com.aliware.edas.async.AsyncEchoService 的 Future 方法标记为 Future 类型的异步调用。

     
    1. @Configuration
    2. public class HsfConfig {
    3. @HSFConsumer(serviceVersion = "1.0.0", futureMethods = "future")
    4. private AsyncEchoService asyncEchoService;
    5. }
  2. 方法在被标记成 Future 类型的异步调用后,同步执行时的方法返回值其实是 null,需要通过 HSFResponseFuture 来获取调用的结果。

    我们在这里通过 TestAsyncController 来进行演示,示例代码如下:

     
    1. @RestController
    2. public class TestAsyncController {
    3.  
    4. @Autowired
    5. private AsyncEchoService asyncEchoService;
    6.  
    7. @RequestMapping(value = "/hsf-future/{str}", method = RequestMethod.GET)
    8. public String testFuture(@PathVariable String str) {
    9.  
    10. String str1 = asyncEchoService.future(str);
    11. String str2;
    12. try {
    13. HSFFuture hsfFuture = HSFResponseFuture.getFuture();
    14. str2 = (String) hsfFuture.getResponse(3000);
    15. } catch (Throwable t) {
    16. t.printStackTrace();
    17. str2 = "future-exception";
    18. }
    19. return str1 + " " + str2;
    20. }
    21. }

    调用 /hsf-future/123 ,可以看到 str1 的值为 null, str2 才是真实的调用返回值 123。

    Spring cloud HSF 集成 HSF 高级特性_第1张图片

  3. 当服务中需要结合一批操作的返回值进行处理时,参考如下的调用方式。

     
    1. @RequestMapping(value = "/hsf-future-list/{str}", method = RequestMethod.GET)
    2. public String testFutureList(@PathVariable String str) {
    3. try {
    4.  
    5. int num = Integer.parseInt(str);
    6. List params = new ArrayList();
    7. for (int i = 1; i <= num; i++) {
    8. params.add(i + "");
    9. }
    10.  
    11. List hsfFutures = new ArrayList();
    12. for (String param : params) {
    13. asyncEchoService.future(param);
    14. hsfFutures.add(HSFResponseFuture.getFuture());
    15. }
    16.  
    17. ArrayList results = new ArrayList();
    18. for (HSFFuture hsfFuture : hsfFutures) {
    19. results.add((String) hsfFuture.getResponse(3000));
    20. }
    21.  
    22. return Arrays.toString(results.toArray());
    23.  
    24. } catch (Throwable t) {
    25. return "exception";
    26. }
    27. }

    Spring cloud HSF 集成 HSF 高级特性_第2张图片

Callback

  1. 使用 Callback 类型的异步调用的消费端,首先创建一个类实现 HSFResponseCallback 接口,并通过 @Async 注解进行配置。

     
    1. @AsyncOn(interfaceName = AsyncEchoService.class,methodName = "callback")
    2. public class AsyncEchoResponseListener implements HSFResponseCallback{
    3. @Override
    4. public void onAppException(Throwable t) {
    5. t.printStackTrace();
    6. }
    7.  
    8. @Override
    9. public void onAppResponse(Object appResponse) {
    10. System.out.println(appResponse);
    11. }
    12.  
    13. @Override
    14. public void onHSFException(HSFException hsfEx) {
    15. hsfEx.printStackTrace();
    16. }
    17. }

    AsyncEchoResponseListener 实现了 HSFResponseCallback 接口,并在 @Async 注解中分别配置 interfaceName 为 AsyncEchoService.class、methodName 为 callback。

    这样,就将 com.aliware.edas.async.AsyncEchoService 的 callback 方法标记为 Callback 类型的异步调用。

  2. 同样,通过 TestAsyncController 来进行演示,示例代码如下:

     
    1. @RequestMapping(value = "/hsf-callback/{str}", method = RequestMethod.GET)
    2. public String testCallback(@PathVariable String str) {
    3.  
    4. String timestamp = System.currentTimeMillis() + "";
    5. String str1 = asyncEchoService.callback(str);
    6. return str1 + " " + timestamp;
    7. }

    执行调用,可以看到如下结果:

    Spring cloud HSF 集成 HSF 高级特性_第3张图片

    消费端将 callback 方法配置为 Callback 类型异步调用时,同步返回结果其实是 null。

    结果返回之后,HSF 会调用 AsyncEchoResponseListener 中的方法,在 onAppResponse 方法中我们可以得到调用的真实返回值。

  3. 如果需要将调用时的上下文信息传递给 callback ,需要使用 CallbackInvocationContext 来实现。

    调用时的示例代码入下:

     
    1. CallbackInvocationContext.setContext(timestamp);
    2. String str1 = asyncEchoService.callback(str);
    3. CallbackInvocationContext.setContext(null);

    AsyncEchoResponseListener 示例代码如下:

     
    1. @Override
    2. public void onAppResponse(Object appResponse) {
    3. Object timestamp = CallbackInvocationContext.getContext();
    4. System.out.println(timestamp + " " +appResponse);
    5. }

    我们可以在控制台中看到输出了 1513068791916 123,证明 AsyncEchoResponseListener 的 onAppResponse 方法通过 CallbackInvocationContext 拿到了调用前传递过来的 timestamp 的内容。

    Spring cloud HSF 集成 HSF 高级特性_第4张图片

你可能感兴趣的:(java)