Activate
之前已经讲到了关于dubbo spi的默认扩展,适配扩展,包装扩展。现在稍微总结一下:
- 普通扩展和默认扩展是实现类
- 包装扩展一般仅仅只是做一层装饰
- 在类上有
Adaptive
注解的适配扩展也是实现类,没有就会通过源码生成,源码通过url拿到真正想要实现的spi对象,没有就还是用默认扩展
还差激活扩展(名字别在意)没有涉及,首先讲一下源码,然后通过filter来举例,增加印象。
ExtensionLoader#getActivateExtension
这个方法有很多不同参数的重载版本,来看一下最终调用的代码。
public List<T> getActivateExtension(URL url, String[] values, String group) {
List<T> exts = new ArrayList<T>();
List<String> names = values == null ? new ArrayList<String>(0) : Arrays.asList(values);
//不需要默认的激活扩展:-default
if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {
//加载
getExtensionClasses();
for (Map.Entry<String, Object> entry : cachedActivates.entrySet()) {
String name = entry.getKey();
Object activate = entry.getValue();
String[] activateGroup, activateValue;
//兼容,cachedActivates的值类型为Object
if (activate instanceof Activate) {
activateGroup = ((Activate) activate).group();
activateValue = ((Activate) activate).value();
} else if (activate instanceof com.alibaba.dubbo.common.extension.Activate) {
activateGroup = ((com.alibaba.dubbo.common.extension.Activate) activate).group();
activateValue = ((com.alibaba.dubbo.common.extension.Activate) activate).value();
} else {
continue;
}
//是否分组匹配:provider和consumer
if (isMatchGroup(group, activateGroup)) {
T ext = getExtension(name);
//1.该filter是否被手动指定激活
if (!names.contains(name)
//2.被手动通过-删除
&& !names.contains(Constants.REMOVE_VALUE_PREFIX + name)
//3.激活条件是否满足
&& isActive(activateValue, url)) {
exts.add(ext);
}
}
}
//通过注解排序
Collections.sort(exts, ActivateComparator.COMPARATOR);
}
//手动指定的激活扩展
List<T> usrs = new ArrayList<T>();
for (int i = 0; i < names.size(); i++) {
String name = names.get(i);
//不是通过-删除的激活条件
if (!name.startsWith(Constants.REMOVE_VALUE_PREFIX)
//不存在删除该名字的条件
&& !names.contains(Constants.REMOVE_VALUE_PREFIX + name)) {
//如果有default,将之前已经手动激活的扩展放到最前面
if (Constants.DEFAULT_KEY.equals(name)) {
if (!usrs.isEmpty()) {
exts.addAll(0, usrs);
usrs.clear();
}
} else {
//缓存已经激活的扩展
T ext = getExtension(name);
usrs.add(ext);
}
}
}
//default后面或者没有default都放到最后面
if (!usrs.isEmpty()) {
exts.addAll(usrs);
}
return exts;
}
代码很简单,复杂的就是激活条件,这里举一些例子,相信只要使用过就能理解。首先假设有a,b,c,d,e五个待激活扩展:
- a,b,c,-default,-a --> b,c
- b,default,e --> b,a,c,d,e(acd顺序由
ActivateComparator
保证) - b,default,e,a,-c --> b,d,e,a
filter
这个接口有spi注解,只有一个方法且只有ProtocolFilterWrapper
这个类在调用。
ProtocolFilterWrapper
public class ProtocolFilterWrapper implements Protocol {
private final Protocol protocol;
//构造方法表明这是一个包装扩展
public ProtocolFilterWrapper(Protocol protocol) {
if (protocol == null) {
throw new IllegalArgumentException("protocol == null");
}
this.protocol = protocol;
}
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
Invoker<T> last = invoker;
//所有被激活的扩展
List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
if (!filters.isEmpty()) {
//保证filter按照顺序执行,即排序第一的最先执行
for (int i = filters.size() - 1; i >= 0; i--) {
final Filter filter = filters.get(i);
final Invoker<T> next = last;
//实现Invoker接口,对invoke方法进行处理
last = new Invoker<T>() {
@Override
public Class<T> getInterface() {
return invoker.getInterface();
}
@Override
public URL getUrl() {
return invoker.getUrl();
}
@Override
public boolean isAvailable() {
return invoker.isAvailable();
}
@Override
public Result invoke(Invocation invocation) throws RpcException {
return filter.invoke(next, invocation);
}
@Override
public void destroy() {
invoker.destroy();
}
@Override
public String toString() {
return invoker.toString();
}
};
}
}
return last;
}
@Override
public int getDefaultPort() {
//直接调用真实的方法
return protocol.getDefaultPort();
}
@Override
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
return protocol.export(invoker);
}
return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
}
@Override
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
return protocol.refer(type, url);
}
return buildInvokerChain(protocol.refer(type, url), Constants.REFERENCE_FILTER_KEY, Constants.CONSUMER);
}
@Override
public void destroy() {
//直接调用真实的方法
protocol.destroy();
}
}
通过它的构造方法,很明显这是一个包装扩展。那么再来看一下它实现的方法,export
和refer
通过buildInvokerChain
做了一些特殊的操作,那么继续看这个特殊处理的方法。首先通过url和key找到激活条件,配合group找到所有满足条件的激活扩展filter,通过之前的讲解这里已经是排好序的,然后倒叙遍历,倒叙排列保证了第一个filter会先被执行。这就是dubbo的filter机制的实现方法,例如echo调用,泛化调用都是通过该机制实现的,也可以通过实现filter接口和spi注册帮助实现一些调用时的扩展。
网友评论