服务分组和版本
- Apache Dubbo的服务分组和版本是强隔离属性
- 服务分组和版本可以实现业务平滑升级
- 服务分组和版本可以实现业务隔离
演示
provider
public class ServiceDemoImpl implements ServiceDemo {
@Override
public String getSelf(String context) {
return "ServiceDemoImpl :" + context;
}
}
public class ServiceDemoImpl2 implements ServiceDemo {
@Override
public String getSelf(String context) {
return "ServiceDemoImpl2 :" + context;
}
}
<bean id="iServiceDemo" class="com.jiangzheng.course.dubbo.provider.service.ServiceDemoImpl" />
<bean id="iServiceDemo2" class="com.jiangzheng.course.dubbo.provider.service.ServiceDemoImpl2" />
<dubbo:service id="serviceDemo" group="service" version="0.0.1" interface="com.jiangzheng.course.dubbo.api.service.ServiceDemo" ref="iServiceDemo"/>
<dubbo:service id="serviceDemo2" group="service2" version="0.0.2" interface="com.jiangzheng.course.dubbo.api.service.ServiceDemo" ref="iServiceDemo2"/>
consumer
<dubbo:reference id="serviceDemo" group="service2" version="0.0.2" interface="com.jiangzheng.course.dubbo.api.service.ServiceDemo"/>
@SpringBootApplication
@ImportResource(locations = {"classpath:springContext-dubbo.xml"})
public class DubboDemoApplication {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ConfigurableApplicationContext context = SpringApplication.run(DubboDemoApplication.class, args);
ServiceDemo serviceDemo = context.getBean("serviceDemo", ServiceDemo.class);
//调用
String result = serviceDemo.getSelf("hello wwy");
/* //获取异步结果
CompletableFuture<String> completableFuture = RpcContext.getContext().getCompletableFuture();
String result = completableFuture.get();*/
System.out.println(result);
}
}
输出结果
ServiceDemoImpl2 :hello wwy
源码解析
首先再注册的时候 因为在provider的配置中是两个 dubbo:service/标签,所有会注册两个上去, consumer在获取的时候 调用org.apache.dubbo.registry.zookeeper.ZookeeperRegistry#lookup方法,我们看下这个方法
@Override
public List<URL> lookup(URL url) {
if (url == null) {
throw new IllegalArgumentException("lookup url == null");
}
try {
//通过url获取提供服务的provider
List<String> providers = new ArrayList<>();
for (String path : toCategoriesPath(url)) {
List<String> children = zkClient.getChildren(path);
if (children != null) {
providers.addAll(children);
}
}
//获取匹配上的provider,查看此方法
return toUrlsWithoutEmpty(url, providers);
} catch (Throwable e) {
throw new RpcException("Failed to lookup " + url + " from zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
}
}
//org.apache.dubbo.registry.support.CacheableFailbackRegistry#toUrlsWithoutEmpty
protected List<URL> toUrlsWithoutEmpty(URL consumer, Collection<String> providers) {
// keep old urls
Map<String, ServiceAddressURL> oldURLs = stringUrls.get(consumer);
// create new urls
Map<String, ServiceAddressURL> newURLs;
URL copyOfConsumer = removeParamsFromConsumer(consumer);
if (oldURLs == null) {
newURLs = new HashMap<>();
for (String rawProvider : providers) {
rawProvider = stripOffVariableKeys(rawProvider);
ServiceAddressURL cachedURL = createURL(rawProvider, copyOfConsumer, getExtraParameters());
if (cachedURL == null) {
logger.warn("Invalid address, failed to parse into URL " + rawProvider);
continue;
}
newURLs.put(rawProvider, cachedURL);
}
} else {
newURLs = new HashMap<>((int) (oldURLs.size() / .75 + 1));
// maybe only default , or "env" + default
for (String rawProvider : providers) {
rawProvider = stripOffVariableKeys(rawProvider);
ServiceAddressURL cachedURL = oldURLs.remove(rawProvider);
if (cachedURL == null) {
//此处会对group、version进行筛选
cachedURL = createURL(rawProvider, copyOfConsumer, getExtraParameters());
if (cachedURL == null) {
logger.warn("Invalid address, failed to parse into URL " + rawProvider);
continue;
}
}
//加入到集合中
newURLs.put(rawProvider, cachedURL);
}
}
stringUrls.put(consumer, newURLs);
// destroy used urls
try {
if (oldURLs != null && oldURLs.size() > 0) {
Long currentTimestamp = System.currentTimeMillis();
for (Map.Entry<String, ServiceAddressURL> entry : oldURLs.entrySet()) {
waitForRemove.put(entry.getValue(), currentTimestamp);
}
if (CollectionUtils.isNotEmptyMap(waitForRemove)) {
if (semaphore.tryAcquire()) {
cacheRemovalScheduler.schedule(new RemovalTask(), cacheRemovalTaskIntervalInMillis, TimeUnit.MILLISECONDS);
}
}
}
} catch (Exception e) {
logger.warn("Failed to evict url for " + consumer, e);
}
//返回
return new ArrayList<>(newURLs.values());
}