欢迎光临我的个人博客:https://www.jelliclecat.cn/
一. Filter原理
最近刚刚接触dubbo,瞬间被dubbo的简洁和扩展性圈粉了,用郭大爷的话来说就是又勾勾又丢丢,一想之美。代码算上测试一共短短12W行,没有像spring那么复杂的继承结构,但是对各种设计模式和架构设计理念的运用又极度的优雅。
跑题了,这里主要记录一下Filter的作用原理。Filter在很多地方都有用到,比如Servlet。Dubbo中也不例外,在一个Invoker被调用之前,可以配置多个Filter去过滤一次调用。Filter的作用可以看做一个AOP,在真正调用的前后做一些工作,并且Filter可以非常方便的层层嵌套。
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);
}
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.size() > 0) {
for (int i = filters.size() - 1; i >= 0; i --) {
final Filter filter = filters.get(i);
final Invoker<T> next = last;
last = new Invoker<T>() {
public Class<T> getInterface() {
return invoker.getInterface();
}
public URL getUrl() {
return invoker.getUrl();
}
public boolean isAvailable() {
return invoker.isAvailable();
}
public Result invoke(Invocation invocation) throws RpcException {
return filter.invoke(next, invocation);
}
public void destroy() {
invoker.destroy();
}
@Override
public String toString() {
return invoker.toString();
}
};
}
}
return last;
}
这段代码可以非常清晰的看到filter是如何被一层一层组装的。
二. 自己模拟实现
image
目录结构如上,Filter和Invoker也超级简单:
public interface Filter {
int invoke(Invoker invoker, int i);
}
public interface Invoker {
int result(int i);
}
看看实现类:
public class InvokerImpl implements Invoker {
@Override
public int result(int i) {
System.out.println("invoker impl");
return i * 2;
}
}
public class FilterA implements Filter{
@Override
public int invoke(Invoker invoker, int i) {
try {
System.out.println("Filter A");
int result = invoker.result(i);
System.out.println("after Filter A");
return result;
}catch (Exception e) {
throw e;
}
}
}
public class FilterB implements Filter {
@Override
public int invoke(Invoker invoker, int i) {
try {
System.out.println("Filter B");
int result = invoker.result(i);
System.out.println("after Filter B");
return result;
} catch (Exception e) {
throw e;
}
}
}
组装filter并测试:
public class Test {
public static void main(String[] args) {
Filter filter1 = new FilterA();
Filter filter2 = new FilterB();
List<Filter> filters = new ArrayList<>();
filters.addAll(Arrays.asList(filter1, filter2));
Invoker last = new InvokerImpl();
// 注意顺序,filter2 -> filter1 -> invoker
for(Filter filter : filters) {
final Invoker next = last;
last = (i) -> filter.invoke(next, i);
}
System.out.println(last.result(1));
}
}
这里要注意组装的顺序,决定最后先调用那个filter。
看看最后的运行结果:
Filter B
Filter A
invoker impl
after Filter A
after Filter B
2
结合以上代码,不难看出filter的执行顺序,filter其实就是一个硬编码的栈,用户可以决定在栈的什么地方做一个操作。