Dubbo的Filter實現入口是在ProtocolFilterWrapper,由於ProtocolFilterWrapper是Protocol的包裝類,因此會在加載的Extension的時候被自動包裝進來,實如今ProtocolFilterWrapper.buildInvokerChain方法數組
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
Invoker<T> last = invoker;
//得到全部符合條件的Filter(已經排好序的)
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;
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;
}
複製代碼
List
public List<T> getActivateExtension(URL url, String key, String group) {
//key service.filter
//獲取該service自定義filter,以逗號隔開
String value = url.getParameter(key);
return getActivateExtension(url, value == null || value.length() == 0 ? null : Constants.COMMA_SPLIT_PATTERN.split(value), group);
}
複製代碼
public List<T> getActivateExtension(URL url, String[] values, String group) {
List<T> exts = new ArrayList<T>();
//自定義filter數組
List<String> names = values == null ? new ArrayList<String>(0) : Arrays.asList(values);
//若是自定義filter包含"-default"就不會加載dubbo自帶的filter
if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {
//經過ExtensionLoader獲取全部的filter
getExtensionClasses();
//遍歷具備Activate註解的,這個cachedActivates是在getExtensionClasses()中放入的
//dubbo自帶的filter都是Activate註解的,不須要手動在配置文件中加入這些filter,
//若是本身也想寫全局的,也能夠加上Activate註解,這樣也會出如今cachedActivates中
for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) {
String name = entry.getKey();
Activate activate = entry.getValue();
//判斷是否符合條件 是否在該組中,分爲provider和consumer
if (isMatchGroup(group, activate.group())) {
//獲得該filter實例
T ext = getExtension(name);
if (!names.contains(name)
&& !names.contains(Constants.REMOVE_VALUE_PREFIX + name)
&& isActive(activate, url)) {
//若是自定義filter不包含該filter,
//而且自定義filter不包含「-」+該filter,而且isActive就放入exts中
//這裏若是不想用dubbo自帶的某個filter就能夠用「-」+filter名稱去除掉
exts.add(ext);
}
}
}
//對這些filter進行排序
Collections.sort(exts, ActivateComparator.COMPARATOR);
}
List<T> usrs = new ArrayList<T>();
//遍歷自定義filter數組
for (int i = 0; i < names.size(); i++) {
String name = names.get(i);
//若是filter名稱不以-開頭而且filter數組不包含「-」+該filter名稱
if (!name.startsWith(Constants.REMOVE_VALUE_PREFIX)
&& !names.contains(Constants.REMOVE_VALUE_PREFIX + name)) {
//若是該名稱爲default
if (Constants.DEFAULT_KEY.equals(name)) {
//若是exts不爲空
if (!usrs.isEmpty()) {
//把usrs加入到exts中並放到前面,並清空usrs,
//這裏和後面實現了自定義filter和dubbo自帶的filter排序功能
//由於看後面最終返回的是exts(有序的)
//舉例 filter="filter1,filter2,filter3,default,filter4"
//最終exts順序就爲filter1,filter2,filter3,dubbo符合條件的filter,filter4
//若是沒有寫default,dubbo自帶的會在自定義的前面
exts.addAll(0, usrs);
, usrs.clear();
}
} else {
//若是不包含就放入usrs中
T ext = getExtension(name);
usrs.add(ext);
}
}
}
//變量完後,把usrs剩下的都放到exts中
if (!usrs.isEmpty()) {
exts.addAll(usrs);
}
return exts;
}
複製代碼
private Map<String, Class<?>> getExtensionClasses() {
//從緩存中獲取
Map<String, Class<?>> classes = cachedClasses.get();
if (classes == null) {
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
//若是沒有就從文件中加載
classes = loadExtensionClasses();
//放到緩存中
cachedClasses.set(classes);
}
}
}
return classes;
}
private Map<String, Class<?>> loadExtensionClasses() {
//獲取該類型的SPI默認值
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if (defaultAnnotation != null) {
String value = defaultAnnotation.value();
if ((value = value.trim()).length() > 0) {
String[] names = NAME_SEPARATOR.split(value);
if (names.length > 1) {
throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
+ ": " + Arrays.toString(names));
}
//設置默認值
if (names.length == 1) cachedDefaultName = names[0];
}
}
Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
//META-INF/dubbo/internal/ 該文件下查找 com.alibaba.dubbo.rpc.Filter並加載
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
//META-INF/dubbo/ 該文件下查找 com.alibaba.dubbo.rpc.Filter
loadDirectory(extensionClasses, DUBBO_DIRECTORY);
//META-INF/services/ 該文件下查找 com.alibaba.dubbo.rpc.Filter
loadDirectory(extensionClasses, SERVICES_DIRECTORY);
//最終Map<String, Class<?>> extensionClasses
return extensionClasses;
}
複製代碼
綜上源碼解析,dubbo是採用本身的SPI機制,一個serviceBean會被不少層東西包裝,其中包含ProtocolFilterWrapper
在轉換爲export的時候,會調用bash
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));
}
複製代碼
構建filter鏈
dubbo的filter也是基於SPI機制,看上面代碼能夠看到他會去 META-INF/dubbo/internal/、META-INF/dubbo/、META-INF/services/ 該文件下查找 com.alibaba.dubbo.rpc.Filter並加載app