pandora-hsf-spring-boot-starter 与 spring boot 的集成

本文描述了使用 Spring Boot 的编程模型在 Pandora Boot 应用中使用 HSF

maven依赖

导入pandora-boot-starter-bom

<dependencyManagement>
    <dependencies>
        <dependency>
            <!-- Import dependency management from Spring Boot -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <!-- http://gitlab.alibaba-inc.com/middleware-container/pandora-boot/wikis/spring-boot-2 -->
            <version>2.5.12</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>com.taobao.pandora</groupId>
            <artifactId>pandora-boot-starter-bom</artifactId>
            <version>2023-07-stable-hsf</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>(注意不是<dependencyManagement>/<dependencies>)下添加依赖(无须写版本):

<dependency>
    <groupId>com.alibaba.boot</groupId>
    <artifactId>pandora-hsf-spring-boot-starter</artifactId>
</dependency>

全局配置

在 application.properties 添加所有 HSF的默认版本信息和客户端超时信息, 样例配置如下:

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

@HSFProvider

注意是com.alibaba.boot.hsf.annotation.HSFProvider,不是com.taobao.hsf.app.spring.util.annotation.HSFProvider

 首先要编写服务提供者

只需要在发布的服务上添加@HSFProvider,其中DemoService是要发布的服务的接口,注意:注解是加在实现类的头上。

@HSFProvider(serviceInterface = DemoService.class)
public class DemoServiceImpl implements DemoService{}

还可以通过该注解为特定的服务设置配置,可以覆盖全局配置。

@HSFProvider(serviceInterface = DemoService.class, serviceGroup = "HSF", serviceVersion = "1.0.1", clientTimeout = 500)
public class DemoServiceImpl implements DemoService{}

@HSFProvider 中的 serviceGroup 和 serviceVersion 以及其他 String 类型的配置都可以支持 Spring 的 property placeholder, 如:

@HSFProvider(serviceInterface = DemoService.class, serviceGroup = "${service.group.name}")
public class DemoServiceImpl implements DemoService{}

注意:springboot默认只扫描main函数所在的package,如果服务在其他的package里,需要配置@componentScan

@ComponentScan(basePackages = "com.taobao.mypackage")

 此前总结:和feign调用类似,但比feign更简洁,此处只需要在实现类上加注解,但是feign需要专门写feignclient,而且feign是针对controller写的,但是hsf是直接对实现类加注解。

假如我要调用其他的服务中的服务,我需要在目前的项目的启动类上加上@componentScan注解,这样才可以将对应服务的对象加载到我的ioc容器中,才可以通过di注入。

接下来就是消费服务了

方法一:直接使用@HSFConsumer注入需要的接口(注意:此处注入的是接口,但是消费提供的时候加注解的地方是实现类上,不要混淆)

@Component
public class DemoClient {
    @HSFConsumer(serviceGroup = "HSF", serviceVersion = "1.0.0")
    private DemoService demoService;
}

如果在配置文件中定义了全局默认配置,那么在serviceGroup和serviceVersion 是可以不需要指定的,如果想指定特定值,可以通过注解属性进行覆盖。当然和服务提供者一样,此处一样可以用占位符

注意:如果在使用全局配置时,同时需要显式配置serviceVersion1.0.0.DAILY,可以使用spring placeholder ${}的方式来处理。

除了这种方式还可以通过配置类配置一次,然后多处直接注入

@Configuration
public class HsfConfig {
    @HSFConsumer(serviceVersion = "2.0.1", serviceGroup = "product", clientTimeout = 10000)
    HelloWorldService helloWorldService;

}

在使用时直接注入即可:

    @Autowired
    HelloWorldService helloWorldService;

 方法二:创建一个Java Configuration,然后可以通过代码方式引入Hsf

@Configuration
public class DemoAutoConfigure {
    @Bean
    public DemoService demoService() {
        return (DemoService) ServiceFactory.consumer()
                .service(DemoService.class)
                .group("HSF")
                .version("1.0.0")
                .sync()
                .subscribe();
    }
}

注入服务

@Autowired
private DemoService demoService;

 第三种方式:使用传统的xml配置文件装配Bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="helloWorldConsumer" class="com.taobao.hsf.app.spring.util.HSFSpringConsumerBean" init-method="init">
        <property name="interfaceName" value="com.acme.DemoService"/>
        <property name="version" value="1.0.0"/>
        <property name="group" value="HSF"/>
    </bean>
</beans>

 然后在对应的启动类上添加@ImportResource导入自定义的xml配置文件

@Bean方式创建 HSFSpringProviderBean 和 HSFSpringConsumerBean

如果使用以上注解出现变量无法注入的问题,可以使用@Bean的配置方式

操作如下:

接口

现有一个DemoService的接口:

public interface DemoService {
    public String hello(String msg);
}

接口的实现

接口的实现是一个Spring bean:

@Service
public class DemoServiceImpl implements DemoService{
    @Override
    public String hello(String msg) {
        return "hello " + msg;
    }
}

配置 HSFSpringProviderBean

@Configuration
public class HsfProviderConfig {
    @Bean(initMethod = "init")
    public HSFSpringProviderBean demoserviceProvider(DemoServiceImpl demoServiceImpl) {
        HSFSpringProviderBean provider = new HSFSpringProviderBean();
        provider.setServiceInterfaceClass(DemoService.class);
        provider.setTarget(demoServiceImpl);
        provider.setServiceVersion("1.0.0");
        provider.setServiceGroup("HSF");
        return provider;
    }
}

配置 HSFSpringConsumerBean

@Configuration
public class HsfConsumerConfig {
    @Bean(initMethod = "init")
    public HSFSpringConsumerBean demoserviceConsumer() {
        HSFSpringConsumerBean consumer = new HSFSpringConsumerBean();
        consumer.setInterfaceClass(DemoService.class);
        consumer.setVersion("1.0.0");
        consumer.setGroup("HSF");
        return consumer;
    }
}

当要使用这个consumer时,直接注入就可以了:

@Autowired
DemoService demoserviceConsumer;

调试支持: 直连某一HSF Server

本功能需要应用显式设置vm arguments为-Dhsf.run.mode=0, 参考HSF文档

在开发阶段, 如果你需要调试, 你需要连接到某一主机上, 这个时候你需要设置一下某一接口调用的目标地址. HSF Service的目标地址可以在 hsfops 服务查询 里查到

spring.hsf.routes.com.acme.DemoService=1.2.3.4

或者通过 HSF LightAPI 支持 中调用 target(ip) 方法来指定。

通过这种方式,你就可以快速将HSF服务调用路由到指定的主机上, 方便你进行调试. 请不要在生产环境使用

单元测试

Pandora Boot 应用的单元测试可以通过 PandoraBootRunner 启动,并与 SpringJUnit4ClassRunner 无缝集成

@RunWith(PandoraBootRunner.class)
@DelegateTo(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
@Component
public class ApplicationTest {

    @HSFConsumer(generic = true)
    DemoService consumer;

    @Test
    public void testInvoke() {
        TestCase.assertEquals("hello : pandora boot", consumer.sayHello("pandora boot"));
    }

    @Test
    public void testGenericInvoke() {
        GenericService service = (GenericService) consumer;
        Object result = service.$invoke("sayHello", new String[]{String.class.getName()}, new Object[]{"pandora boot"});
        TestCase.assertEquals("hello : pandora boot", result);
    }
}

在单元测试中,往往需要 mock 掉服务调用的方法,下面给出了使用 Mockito 的范例:

    @Test
    public void testMock() {
        DemoService mock = Mockito.mock(DemoService.class, AdditionalAnswers.delegatesTo(consumer));
        Mockito.when(mock.sayHello("ping")).thenReturn("pong");
        TestCase.assertEquals("pong", mock.sayHello("ping"));
        TestCase.assertEquals("hello : pandora boot", mock.sayHello("pandora boot"));
    }

HSF LightAPI 支持

在 如何消费HSF服务(方法二) 中初步展示了 HSF lightapi 的用法。HSF lightapi 提供了一种方便的编程方式给开发人员提供 HSF 服务或者消费 HSF 服务。

服务消费方
DemoService demoService = (DemoService) ServiceFactory.consumer()
    .service(DemoService.class)
    .group("HSF")
    .version("1.0.0")
    .generic()
    .sync()
    .subscribe();
服务提供方
ServiceFactory.provider()
    .service(com.acme.DemoService)
    .name("demo")
    .impl(new com.acme.DemoServiceImpl())
    .group("HSF")
    .version("1.0.0")
    .timeout(3000)
    .publish();

HSF不仅支持同步调用,而且还支持异步调用,共有两种方式,第一种是在调用完毕后在需要获取结果的地方,执行以下代码可获得执行结果。

调用执行后,可以通过以下的代码获取到执行结果。更详细的用法请参阅 HSF Future 调用文档

HSFFuture hsfFuture = HSFResponseFuture.getFuture();
...
Object result = future.getResponse(5000);

第二种方式,远程调用结束后自动回调调用方的回调函数 代码如下:

通过实现 HSFResponseCallback 以及在实现类上标注 @AsyncOn 可以很方便的支持 HSF Consumer 的 callback listener。更详细的用法请参阅 HSF 异步回调文档

@AsyncOn(interfaceName = Echo.class, methodName = "ping")
public class EchoServiceResponseListener implements HSFResponseCallback {

    @Override
    public void onAppException(Throwable t) {}

    @Override
    public void onAppResponse(Object appResponse) {}

    @Override
    public void onHSFException(HSFException hsfEx) {}
}

HSF的一些配置参数说明

HSF会从System Properties中读取相关的一些配置项, 相关的配置项说明在 http://gitlab.alibaba-inc.com/middleware/hsf2-0/wikis/vnarguments

一些特别的说明:

  • project.name: 从 spring.application.name 以及 project.name 中获取应用名

配置的覆盖关系

对于 @HSFProvider@HSFConsumer 这两个 annotation 上定义的值与 application.properties 中定义的值,是存在覆盖关系的: annotation 上的默认值 < application.properties 上全局的值 (比如 spring.hsf.version) < annotation 上指定的值 < application.properties 上为单独服务指定的值。简单的说,覆盖关系可以用下面两个原则来总结:

  1. 外面的配置覆盖里面的配置:-D参数 > application.properties > Annotation
  2. 显式指定的配置优先默认配置

进一步的,在 application.properties 中可以为各个 interface 配置 group, version, 或者 timeout:

spring.hsf.groups.com.acme.DemoService = HSF
spring.hsf.versions.com.acme.DemoService = 1.0.0
spring.hsf.timeouts.com.acme.DemoService = 2000

注意在这种情况下前缀是复数 spring.hsf.groupsspring.hsf.versionsspring.hsf.timeouts

通过复数形式对特定服务单独指定配置的还有:

  • spring.hsf.configserver-centers: 服务多注册中心发布
  • spring.hsf.delay-publishes: 优雅上下线
  • spring.hsf.enables: 暂时禁用特定服务。比如spring.hsf.enables.com.test.pandora.hsf.HelloWorldService=false

补充说明:非 Spring Boot 场景

在非 Spring Boot 场景中同样可以使用 @HSFProvider 以及 @HSFConsumer,示例如下:

public class Application {
    public static void main(String[] args) {
        PandoraBootstrap.run(args);
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(HsfProviderAutoConfiguration.class);
        context.scan(DemoService.class.getPackage().getName());
        context.refresh();
        PandoraBootstrap.markStartupAndWait();
    }
}

@HSFProvider(serviceInterface = DemoService.class)
public class DemoServiceImpl implements DemoService {
    @Override
    public String sayHello(String name) {
        return "hello : " + name;
    }
}

需要注意的是,在这种使用场景下,需要在 pom.xml 中显示的排除掉 spring-boot-autoconfigure 的依赖

<dependency>
    <groupId>com.alibaba.boot</groupId>
    <artifactId>pandora-hsf-spring-boot-starter</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </exclusion>
    </exclusions>
</dependency>

集成 Hystrix

Endpoint

当启用了spring boot endpoint时,可以访问: http://localhost:7002/hsf

参考文档

 

  • 23
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值