在介绍责任链设计模式在Dubbo中的应用之前,先来了解一下该设计模式。
责任链模式定义
这里引用菜鸟教程的定义
责任链模式通过将多个处理器(处理对象)以链式结构连接起来,使得请求沿着这条链传递,直到有一个处理器处理该请求为止。
责任链模式允许多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求。
责任链设计模式属于行为型模式
使用场景
- 当有多个对象可以处理请求,且具体由哪个对象处理由运行时决定时。
- 当需要向多个对象中的一个提交请求,而不想明确指定接收者时。
优缺点
优点
- 降低耦合度:发送者和接收者之间解耦。
- 简化对象:对象不需要知道链的结构。
- 灵活性:通过改变链的成员或顺序,动态地新增或删除责任。
- 易于扩展:增加新的请求处理类很方便。
缺点
- 请求未被处理:不能保证请求一定会被链中的某个处理者接收。
- 性能影响:可能影响系统性能,且调试困难,可能导致循环调用。
- 难以观察:运行时特征不明显,可能妨碍除错。
菜鸟教程的示例
具体代码可以到菜鸟教程看一下,这里不再赘述
以上定义均采于菜鸟教程,dubbo中的应用才是本篇的重点!
Dubbo中的应用
版本:3.2.6
构建责任链
首先我们来看下DefualtFilterChainBuilder#buildInokerChain()
方法,此方法会为传入的Invoker
构建一个Filter
责任链,目的是在进行Invoker
调用invoke
时,能够去进行一系列的Filter
操作,实现些扩展的功能。
java
/**
* build consumer/provider filter chain
*/
@Override
public <T> Invoker<T> buildInvokerChain(final Invoker<T> originalInvoker, String key, String group) {
Invoker<T> last = originalInvoker;
URL url = originalInvoker.getUrl();
List<ModuleModel> moduleModels = getModuleModelsFromUrl(url);
List<Filter> filters;
if (moduleModels != null && moduleModels.size() == 1) {
// 通过spi机制获取所有Filter的Activate扩展点
filters = ScopeModelUtil.getExtensionLoader(Filter.class, moduleModels.get(0))
.getActivateExtension(url, key, group);
} else if (moduleModels != null && moduleModels.size() > 1) {
filters = new ArrayList<>();
List<ExtensionDirector> directors = new ArrayList<>();
for (ModuleModel moduleModel : moduleModels) {
List<Filter> tempFilters = ScopeModelUtil.getExtensionLoader(Filter.class, moduleModel)
.getActivateExtension(url, key, group);
filters.addAll(tempFilters);
directors.add(moduleModel.getExtensionDirector());
}
filters = sortingAndDeduplication(filters, directors);
} else {
filters = ScopeModelUtil.getExtensionLoader(Filter.class, null).getActivateExtension(url, key, group);
}
// 为每个Filter的Invoker设置next节点
if (!CollectionUtils.isEmpty(filters)) {
for (int i = filters.size() - 1; i >= 0; i--) {
final Filter filter = filters.get(i);
final Invoker<T> next = last;
last = new CopyOfFilterChainNode<>(originalInvoker, next, filter);
}
return new CallbackRegistrationInvoker<>(last, filters);
}
return last;
}
责任链构建过程
一:传入原始Node
,此处为originalInvoker
二:通过SPI扩展机制
中的getActivateExtension
获取所有Filter
列表
三:将所有Filter
循环,再循环中,每个Node
里都有next
节点,设置每个Node
的next
节点,next
节点和originalInvoker
和Filter
共通构造一个新的Node
四:最后,将构建的最后一个Node
作为last
节点返回
之后,我们以consumer端服务调用为例,看一下在invoke时,FilterChain是如何生效的
通过调试可知,优先执行CallbackRegistrationInvoker
下的invoke方法
java
@Override
public Result invoke(Invocation invocation) throws RpcException {
Result asyncResult = filterInvoker.invoke(invocation);
// 。。。。。。
return asyncResult;
}
此方法将之前构建InvokerChain时,得到的last,即最后一个节点,filterInvoker进行invoke调用
再往下,调用到CopyOfFilterChainNode
类的invoke方法
java
@Override
public Result invoke(Invocation invocation) throws RpcException {
Result asyncResult;
try {
InvocationProfilerUtils.enterDetailProfiler(
invocation, () -> "Filter " + filter.getClass().getName() + " invoke.");
asyncResult = filter.invoke(nextNode, invocation);
// ................此处源码省略
return asyncResult;
}
发现此处会去调用BaseFilter的invoke方法
java
/**
* Always call invoker.invoke() in the implementation to hand over the request to the next filter node.
*/
Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException;
实现BaseFilter接口的类有很多,我们来举一个例子,通过调试,会发现先进入到ConsumerContextFilter,可以说,这个filter就是之前build出来的last节点,其中,我们看下忽略invoke中的业务层代码,只看最后的invoker.invoke方法
java
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
// ........................
return invoker.invoke(invocation);
}
完成调用后,会使用invoker
去调用invoke
,此时的invoker
的类型是CopyOfFilterChainNode
,因此每次调用完,都会回到前面的CopyOfFilterChainNode
的invoke
方法,在这个方法中,又会继续向下传入nextNode
,来让nextNode
进行invoke
调用,以此类推,直到最后一个originalInvoker
执行完invoke
之后结束。
总结
到此,dubbo
中FilterChain
的例子就结束了,其中,运用了责任链设计模式,其实就是先构建这个链路,将各个节点通过nextNode
连接起来,然后使用lastNode
去调用,每次调用时将下一个要调用的节点传入,依次执行,直到最后一个不包含nextNode
的节点执行完毕,整个过程就结束了。