引入接口jar
将jar包 install到本地maven仓库
在windows的cmd下运行如下指令
mvn install:install-file -DgroupId=com.lczyfz.cscrawler -DartifactId=api -Dversion=1.0-SNAPSHOT -Dpackaging=jar -Dfile=E:\ cscrawler.jar
然后在pom文件中引入
<!-- 服务化API依赖 -->
<dependency>
<groupId>com.lczyfz.cscrawler</groupId>
<artifactId>api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
或者将jar放到工程lib中
<dependency>
<groupId>bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
<version>1.13</version>
<systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/UserAgentUtils-1.13.jar</systemPath>
</dependency>
调用说明
在调用的类引入
import com.alibaba.dubbo.config.annotation.Reference;
使用注解注入对象
@Reference
TestCrawlerApi testCrawlerApi;
//调用对象的方法
System.out.println("===Service====" + testCrawlerApi.sayCrawler("Service"));
发布说明
创建api
package com.lczyfz.cscrawler.api;
/**
* Created by maple on 2019-01-23.
*/
public interface TestCrawlerApi {
public String sayCrawler(String name);
}
实现接口,在类引入
import com.alibaba.dubbo.config.annotation.Reference;
import com.lczyfz.cscrawler.api.TestCrawlerApi;
使用@Service
package com.lczyfz.cscrawler.modules.test.service;
import com.alibaba.dubbo.config.annotation.Reference;
import com.lczyfz.cscrawler.api.TestCrawlerApi;
import com.lczyfz.csstorage.api.TestApi;
import org.springframework.stereotype.Service;
/**
* Created by maple on 2019-01-23.
*/
@org.springframework.stereotype.ServiceService
@com.alibaba.dubbo.config.annotation.Service
public class TryApiService implements TestCrawlerApi{
@Override
public String sayCrawler(String name) {
return "Crawler " + name;
}
}
常用配置说明
*启动时检查
@Reference(check = false)
Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能及早发现问题,默认 check="true"。
可以通过 check="false" 关闭检查,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。
另外,如果你的 Spring 容器是懒加载的,或者通过 API 编程延迟引用服务,请关闭 check,否则服务临时不可用时,会抛出异常,拿到 null 引用,如果 check="false",总是会返回引用,当服务恢复时,能自动连上。
*多版本
当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。
可以按照以下的步骤进行版本迁移:
在低压力时间段,先升级一半提供者为新版本
再将所有消费者升级为新版本
然后将剩下的一半提供者升级为新版本
老版本服务提供者配置:
@com.alibaba.dubbo.config.annotation.Service(version = "1.0.0")
新版本服务提供者配置:
@com.alibaba.dubbo.config.annotation.Service(version = "2.0.0")
老版本服务消费者配置:
@Reference(version = "1.0.0")
新版本服务消费者配置:
@Reference(version = "2.0.0")
*回声测试
回声测试用于检测服务是否可用,回声测试按照正常请求流程执行,能够测试整个调用是否通畅,可用于监控。
所有服务自动实现 EchoService 接口,只需将任意服务引用强制转型为 EchoService,即可使用。
// 远程服务引用
EchoService echoService = (EchoService) memberService; // 强制转型为EchoService
// 回声测试可用性
String status = echoService.$echo("OK");
assert(status.equals("OK"));
上下文信息
上下文中存放的是当前调用过程中所需的环境信息。所有配置信息都将转换为 URL 的参数,参见 schema 配置参考手册 中的对应URL参数一列。
RpcContext 是一个 ThreadLocal 的临时状态记录器,当接收到 RPC 请求,或发起 RPC 请求时,RpcContext 的状态都会变化。比如:A 调 B,B 再调 C,则 B 机器上,在 B 调 C 之前,RpcContext 记录的是 A 调 B 的信息,在 B 调 C 之后,RpcContext 记录的是 B 调 C 的信息。
- 服务消费方
// 远程调用
xxxService.xxx();
// 本端是否为消费端,这里会返回true
boolean isConsumerSide = RpcContext.getContext().isConsumerSide();
// 获取最后一次调用的提供方IP地址
String serverIP = RpcContext.getContext().getRemoteHost();
// 获取当前服务配置信息,所有配置信息都将转换为URL的参数
String application = RpcContext.getContext().getUrl().getParameter("application");
// 注意:每发起RPC调用,上下文状态会变化
yyyService.yyy();
- 服务提供方
public class XxxServiceImpl implements XxxService {
public void xxx() {
// 本端是否为提供端,这里会返回true
boolean isProviderSide = RpcContext.getContext().isProviderSide();
// 获取调用方IP地址
String clientIP = RpcContext.getContext().getRemoteHost();
// 获取当前服务配置信息,所有配置信息都将转换为URL的参数
String application = RpcContext.getContext().getUrl().getParameter("application");
// 注意:每发起RPC调用,上下文状态会变化
yyyService.yyy();
// 此时本端变成消费端,这里会返回false
boolean isProviderSide = RpcContext.getContext().isProviderSide();
}
}
访问日志
如果你想记录每一次请求信息,可开启访问日志,类似于apache的访问日志。注意:此日志量比较大,请注意磁盘容量。
将访问日志输出到当前应用的log4j日志:
<dubbo:protocol accesslog="true" />
*性能调优参数
- delay 默认0 延迟注册服务时间(毫秒) ,设为-1时,表示延迟到Spring容器初始化完成时暴露服务
- timeout 默认1000 远程服务调用超时时间(毫秒)
- retries 默认 2 远程服务调用重试次数,不包括第一次调用,不需要重试请设为0
本地存根
远程服务后,客户端通常只剩下接口,而实现全在服务器端,但提供方有些时候想在客户端也执行部分逻辑,比如:做 ThreadLocal 缓存,提前验证参数,调用失败后伪造容错数据等等,此时就需要在 API 中带上 Stub,客户端生成 Proxy 实例,会把 Proxy 通过构造函数传给 Stub,然后把 Stub 暴露给用户,Stub 可以决定要不要去调 Proxy。
/user-guide/images/stub.jpg在 spring 配置文件中按以下方式配置:
@com.alibaba.dubbo.config.annotation.Service(stub = "com.foo.BarServiceStub")
提供 Stub 的实现 :
package com.foo;
public class BarServiceStub implements BarService {
private final BarService barService;
// 构造函数传入真正的远程代理对象
public (BarService barService) {
this.barService = barService;
}
public String sayHello(String name) {
// 此代码在客户端执行, 你可以在客户端做ThreadLocal本地缓存,或预先验证参数是否合法,等等
try {
return barService.sayHello(name);
} catch (Exception e) {
// 你可以容错,可以做任何AOP拦截事项
return "容错数据";
}
}
}
*本地伪装
本地伪装 通常用于服务降级,比如某验权服务,当服务提供方全部挂掉后,客户端不抛出异常,而是通过 Mock 数据返回授权失败。
在 spring 配置文件中按以下方式配置:
@Reference(mock = "com.foo.BarServiceMock")
在工程中提供 Mock 实现 :
package com.foo;
public class BarServiceMock implements BarService {
public String sayHello(String name) {
// 你可以伪造容错数据,此方法只在出现RpcException时被执行
return "容错数据";
}
}
如果服务的消费方经常需要 try-catch 捕获异常,如:
Offer offer = null;
try {
offer = offerService.findOffer(offerId);
} catch (RpcException e) {
logger.error(e);
}
请考虑改为 Mock 实现,并在 Mock 实现中 return null。如果只是想简单的忽略异常,在 2.0.11
以上版本可用:
<dubbo:reference interface="com.foo.BarService" mock="return null" />
网友评论