SOFABoot 为开发人员提供了三种方式来发布和引用 JVM 服务:
- XML 方式
- Annotation 方式
- 编程 API 方式
此外本文还介绍了在这三种方式中如何使用 uniqueId。
XML 方式
服务发布
- 定义一个 Bean:
<bean id="sampleService" class="com.alipay.sofa.runtime.test.service.SampleServiceImpl">
- 通过 SOFA 提供的 Spring 扩展标签来将上面的 Bean 发布成一个 JVM 服务。
<sofa:service interface="com.alipay.sofa.runtime.test.service.SampleService" ref="sampleService">
<sofa:binding.jvm/>
</sofa:service>
上述配置中的
interface
指的是需要发布成服务的接口,ref
指向的是需要发布成 JVM 服务的 Bean。至此,已经完成了一个 JVM 服务的发布。
服务引用
使用 Spring 扩展标签引用服务:
<sofa:reference interface="com.alipay.sofa.runtime.test.service.SampleService" id="sampleServiceRef">
<sofa:binding.jvm/>
</sofa:service>
字段说明:
interface
是服务的接口,需要和发布服务时配置的 interface 一致。id
属性的含义同 Spring BeanId。
上述配置会生成一个 id 为 sampleServiceRef
的 Spring Bean,您可以将这个 Bean 注入到当前 SOFABoot 模块 Spring 上下文的任意地方。
说明:
service
与reference
标签还支持 RPC 服务发布,可参考 RPC 服务发布与引用。
Annotation 方式
除了通过 XML 方式发布 JVM 服务和引用之外,SOFABoot 还提供了 Annotation 的方式来发布和引用 JVM 服务。通过 Annotation 方式发布 JVM 服务,只需要在实现类上加一个 @SofaService
注解即可,如下:
说明:
- 如果一个服务已经被加上了
@SofaService
的注解,它就不能再用 XML 的方式去发布服务了,选择一种方式发布服务,而不是两种混用。@SofaService
的作用是将一个 Bean 发布成一个 JVM 服务,这意味着虽然您可以不用再写<sofa:service/>
的配置,但是还是需要事先将@SofaService
所注解的类配置成一个 Spring Bean。
@SofaService
public class SampleImpl implements SampleInterface {
public void test() {
}
}
在使用 XML 配置 <sofa:service/>
时,配置了一个 interface 属性,但是在使用 @SofaService
注解时,却没有看到有配置服务接口的地方。这是因为当被 @SofaService
注解的类只有一个接口的时候,框架会直接采用这个接口作为服务的接口。而当被 @SofaService
注解的类实现了多个接口时,可以设置 @SofaService
的 interfaceType
字段来指定服务接口,例如:
@SofaService(interfaceType=SampleInterface.class)
public class SampleImpl implements SampleInterface, Serializable {
public void test() {
}
}
与 @SofaService
对应,@SofaReference
用来引用一个 JVM 服务。假设要在一个 Spring Bean 中使用 SampleJvmService 这个 JVM 服务,那么只需要在字段上加上一个 @SofaReference
的注解即可:
public class SampleServiceRef {
@SofaReference
private SampleService sampleService;
}
与 @SofaService
类似,在 @SofaReference
上没有指定服务接口。这是因为 @SofaReference
在不指定服务接口时,会采用被注解字段的类型作为服务接口,您也可以通过设定 @SofaReference
的 interfaceType
属性来指定:
public class SampleServiceRef {
@SofaReference(interfaceType=SampleService.class)
private SampleService sampleService;
}
使用 @SofaService
注解发布服务时,需要在实现类上打上 @SofaService
注解;在 Spring Boot 使用 Bean Method 创建 Bean 时,会导致 @Bean
和 @SofaService
分散在两处,而且无法对同一个实现类使用不同的 uniqueId。因此自 SOFABoot 2.6.0 版本起,支持 @SofaService
作用在 Bean Method 之上,例如:
@Configuration
public class SampleSofaServiceConfiguration {
@Bean("sampleSofaService")
@SofaService(uniqueId = "service1")
SampleService service() {
return new SampleServiceImpl("");
}
}
同样为了方便在 Spring Boot Bean Method 使用注解 @SofaReference
引用服务,自 SOFABoot 2.6.0 版本起,支持在 Bean Method 参数上使用 @SofaReference
注解引用 JVM 服务,例如:
@Configuration
public class MultiSofaReferenceConfiguration {
@Bean("sampleReference")
TestService service(@Value("$spring.application.name") String appName,
@SofaReference(uniqueId = "service") SampleService service) {
return new TestService(service);
}
}
编程 API 方式
SOFABoot 为 JVM 服务的发布和引用提供了一套编程 API 方式,方便直接在代码中发布和引用 JVM 服务,与 Spring 的 ApplicationContextAware
类似,为使用编程 API 方式,首先需要实现 ClientFactoryAware
接口获取编程组件 API:
public class ClientFactoryBean implements ClientFactoryAware {
private ClientFactory clientFactory;
@Override
public void setClientFactory(ClientFactory clientFactory) {
this.clientFactory = clientFactory;
}
}
以 SampleService
为例,使用 clientFactory
通过编程 API 方式发布 JVM 服务:
ServiceClient serviceClient = clientFactory.getClient(ServiceClient.class);
ServiceParam serviceParam = new ServiceParam();
serviceParam.setInstance(new SampleServiceImpl());
serviceParam.setInterfaceType(SampleService.class);
serviceClient.service(serviceParam);
在上述示例代码中:
- 通过
clientFactory
获得ServiceClient
对象。 - 构造
ServiceParam
对象,ServiceParam
对象包含发布服务所需参数,通过setInstance
方法来设置需要被发布成 JVM 服务的对象,setInterfaceType
来设置服务的接口。 - 调用
ServiceClient
的service
方法,发布一个 JVM 服务。
通过编程 API 方式引用 JVM 服务的代码也是类似的:
ReferenceClient referenceClient = clientFactory.getClient(ReferenceClient.class);
ReferenceParam<SampleService> referenceParam = new ReferenceParam<SampleService>();
referenceParam.setInterfaceType(SampleService.class);
SampleService proxy = referenceClient.reference(referenceParam);
同样,引用一个 JVM 服务只需要:
- 从
ClientFactory
中获取一个ReferenceClient
。 - 与发布一个服务类似,构造出一个
ReferenceParam
。 - 设置好服务的接口。
- 调用
ReferenceClient
的reference
方法即可。
说明:通过动态客户端创建的
Reference
对象是一个非常重的对象,使用时不要频繁创建,自行做好缓存,否则可能存在内存溢出的风险。
uniqueId
有些时候,针对一个接口,可能会需要发布两个服务,分别对应到不同的实现。继续上述 sampleService
的例子,可能有两个 SampleService
的实现,这两个实现都需要发布成 JVM Service。按照前面的教程,采用 XML 的方式,可以用下面这种方式进行配置:
<sofa:service interface="com.alipay.sofa.runtime.test.service.SampleService" ref="sampleService1">
</sofa:service>
<sofa:service interface="com.alipay.sofa.runtime.test.service.SampleService" ref="sampleService2">
</sofa:service>
上面的服务发布并无问题,但是当需要引用服务时,则会出现问题,例如使用以下配置引用服务:
<sofa:reference interface="com.alipay.sofa.runtime.test.service.SampleService" id="sampleService">
</sofa:reference>
从此配置中,无法得知这个 JVM 引用到底引用的是哪个 JVM 服务。
为了解决此问题,SOFABoot 引入了 uniqueId 的概念,针对服务接口相同的 JVM 服务,可以通过 uniqueId 来进行区分。
-
上面的服务发布的代码在加入 uniqueId 后,就可以改为:
<sofa:service interface="com.alipay.sofa.runtime.test.service.SampleService" ref="sampleService1" unique-id="ss1">
</sofa:service>
<sofa:service interface="com.alipay.sofa.runtime.test.service.SampleService" ref="sampleService2" unique-id="ss2">
</sofa:service>
-
在引用服务的时候,您可以通过指定 uniqueId 使用不同服务:
- 如要使用
sampleService1
的服务,可指定unique-id
为ss1
,例如:<sofa:reference interface="com.alipay.sofa.runtime.test.service.SampleService" id="sampleService" unique-id="ss1">
</sofa:reference>
- 如要使用
sampleService2
的服务,可指定unique-id
为ss2
,例如:<sofa:reference interface="com.alipay.sofa.runtime.test.service.SampleService" id="sampleService" unique-id="ss2">
</sofa:reference>
- 如要使用
上述例子是在 XML 方式中使用 uniqueId。对于另外两种方式,使用方法如下:
- 使用 Annotation 方式发布 JVM 服务和引用时,可以通过设置
@SofaService
和@SofaReference
的 uniqueId 属性来设置 uniqueId。 - 使用编程 API 方式发布或者引用 JVM 服务时,可以通过
ServiceParam
和ReferenceParam
的 setUniqueId 方法来设置 uniqueId。
原创文章,作者:网友投稿,如若转载,请注明出处:https://www.cloudads.cn/archives/33945.html