Dubbo过滤器 - ClassLoaderFilter
概述
ClassLoaderFilter 是服务提供端的一个 Filter 实现,用于切换当前工作线程的类加载器到接口的类加载器,以便和接口的类加载器的上下文一起工作。
ClassLoaderFilter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| Activate(group = Constants.PROVIDER, order = -30000) public class ClassLoaderFilter implements Filter {
@Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { ClassLoader ocl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(invoker.getInterface().getClassLoader()); try { return invoker.invoke(invocation); } finally { Thread.currentThread().setContextClassLoader(ocl); } } }
|
ClassLoaderFilter 的逻辑:首先获取当前线程关联的 ClassLoader,然后将其 ClassLoader 设置为 invoker.getInterface().getClassLoader(),也就是加载服务接口类的类加载器;之后执行 invoker.invoke() 方法,执行后续的 Filter 逻辑以及业务逻辑;最后,将当前线程关联的 ClassLoader 重置为原来的 ClassLoader ocl 。
双亲委派模型
如果 ClassA 和 ClassB 都是同一个类加载器加载的,则它们之间是可以相互访问的。如果 ClassA 和 ClassB 是不同的类加载器加载的,示例图如下:

根据双亲委派模型,如果 ClassA 要访问 ClassB,大致流程如下:
- ClassA 会从 ClassLoaderA 中查找 ClassB,看是否已经加载。
- 没有找到 ClassB 则会继续往上层查找,看父类加载器 ParentClassLoader 是否可以查找到 ClassB,如果找不到会继续往上层父类加载器查找。
- 最终没有找到,会抛出 ClassNotFoundException 异常。
如果要实现违反双亲委派模型来查找 Class,通常会使用上下文类加载器 ContextClassFilter 。
QA
Q: ClassLoaderFilter 的具体作用?
A: Dubbo 框架线程的类加载器可能和服务接口的类加载器不是同一个,而当前框架线程中又需要获取服务接口的类加载中的一些 Class,为了避免出现 ClassNotFoundException,此时只需要将框架线程的类加载器切换到加载了接口定义的类加载器,进而就能获得这个类加载中的 Class 。
Extra: Dubbo 中进行序列化优化时,会根据 Invoker 中配置的 optimizer
参数获取扩展的自定义序列化处理类,这些外部引入的序列化类在框架的类加载器中肯定没有,因此需要使用 Invoker 的类加载器获取对应的类。
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 47 48 49 50 51 52
| +--- DubboProtocol
private void optimizeSerialization(URL url) throws RpcException { String className = url.getParameter(Constants.OPTIMIZER_KEY, "");
if (StringUtils.isEmpty(className) || optimizers.contains(className)) { return; }
logger.info("Optimizing the serialization process for Kryo, FST, etc...");
try {
Class clazz = Thread.currentThread().getContextClassLoader().loadClass(className);
if (!SerializationOptimizer.class.isAssignableFrom(clazz)) { throw new RpcException("The serialization optimizer " + className + " isn't an instance of " + SerializationOptimizer.class.getName()); }
SerializationOptimizer optimizer = (SerializationOptimizer) clazz.newInstance();
if (optimizer.getSerializableClasses() == null) { return; }
for (Class c : optimizer.getSerializableClasses()) { SerializableClassRegistry.registerClass(c); }
optimizers.add(className); } catch (ClassNotFoundException e) { throw new RpcException("Cannot find the serialization optimizer class: " + className, e); } catch (InstantiationException e) { throw new RpcException("Cannot instantiate the serialization optimizer class: " + className, e); } catch (IllegalAccessException e) { throw new RpcException("Cannot instantiate the serialization optimizer class: " + className, e); } }
|
小结
本篇文件简单介绍了 Dubbo Filter 之 服务端的 ClassLoader 过滤器,它的作用就是用于切换当前工作线程的类加载器到接口的类加载器,以便和接口的类加载器的上下文一起工作。