Filter 的实现原理

一. Filter原理

最近刚刚接触dubbo,瞬间被dubbo的简洁和扩展性圈粉了,用郭大爷的话来说就是又勾勾又丢丢,一想之美。代码算上测试一共短短12W行,没有像spring那么复杂的继承结构,但是对各种设计模式和架构设计理念的运用又极度的优雅。

跑题了,这里主要记录一下Filter的作用原理。Filter在很多地方都有用到,比如Servlet。Dubbo中也不例外,在一个Invoker被调用之前,可以配置多个Filter去过滤一次调用。Filter的作用可以看做一个AOP,在真正调用的前后做一些工作,并且Filter可以非常方便的层层嵌套。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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是如何被一层一层组装的。

二. 自己模拟实现

目录结构如上,Filter和Invoker也超级简单:

1
2
3
4
5
6
7
public interface Filter {
int invoke(Invoker invoker, int i);
}

public interface Invoker {
int result(int i);
}

看看实现类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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并测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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。

看看最后的运行结果:

1
2
3
4
5
6
Filter B
Filter A
invoker impl
after Filter A
after Filter B
2

结合以上代码,不难看出filter的执行顺序,filter其实就是一个硬编码的栈,用户可以决定在栈的什么地方做一个操作。

我不喝咖啡,但是我相信知识有价。