sofastack / sofa-ark

SOFAArk is a light-weight,java based classloader isolation framework.
https://www.sofastack.tech/projects/sofa-boot/sofa-ark-readme/
Apache License 2.0
1.57k stars 500 forks source link

在export的类中寻找,如果两个plugin导出相同的包名是如何处理的? #237

Closed johnyannj closed 5 years ago

johnyannj commented 5 years ago

Your question

我在阅读ark的源码,读到 com.alipay.sofa.ark.container.service.classloader.BizClassLoader 寻找类的过程。 第五步是寻找export的类 resolveExportClass(name)

他会调用com.alipay.sofa.ark.container.service.classloader.ClassLoaderServiceImpl#findExportClassLoader 找到一个classloader,

如果有两个相同export package的plugin。 pluginA 和pluginB。

如果要查找的类是在PluginB里面,而仅到PluginA里找不到就结束了,会不会就找不到这个类了?

Your scenes

因为Plugin是同一个公司开发的,导出的包名可能是一样的。

Your advice

com.alipay.sofa.ark.container.service.classloader.ClassLoaderServiceImpl#exportNodeAndClassLoaderMap 是不是应该记录 导出包名 和一个List的关系?

Environment

QilongZhang commented 5 years ago

不会记录list,因为运行时同一个类智能委托到唯一的 ClassLoader 加载。如果存在多个 Plugin 导出相同的类,以 Plugin 的优先级为准。

johnyannj commented 5 years ago

Hi @QilongZhang 我说的不是导出类,是导出package, ark 不是还可以指定导出package吗?

QilongZhang commented 5 years ago

Hi @QilongZhang 我说的不是导出类,是导出package, ark 不是还可以指定导出package吗?

和类是一样的,优先级高的 Plugin 加载.

johnyannj commented 5 years ago

@QilongZhang 可能我没表达清楚

PluginA 导出com.alipay.test 优先级高 PluginB 也导出com.alipay.test

类com.alipya.test.MyClass 在PluginB里。

com.alipay.sofa.ark.container.service.classloader.ClassLoaderServiceImpl#findExportClassLoader 可能找到的是PluginA的classLoader,而导致无法找到这个类。

QilongZhang commented 5 years ago

@QilongZhang 可能我没表达清楚

PluginA 导出com.alipay.test 优先级高 PluginB 也导出com.alipay.test

类com.alipya.test.MyClass 在PluginB里。

com.alipay.sofa.ark.container.service.classloader.ClassLoaderServiceImpl#findExportClassLoader 可能找到的是PluginA的classLoader,而导致无法找到这个类。

这种情况下会报 CNF 错误,在 OSGi 规范实现的 Equinox 框架中,它会校验是否存在多个 Bundle 导出相同的 Package,存在就会报错。在 Ark 实现中,不会做这个校验,以优先级最高的 Plugin 导出为准,如果加载失败,就会报错。

johnyannj commented 5 years ago

hi @QilongZhang 我理解了这个设计原则。

但是,我觉得这种情况还是很常见的。 因为相同单位不同部门开发的插件,可能都会简单的设置 把“com.公司名” 下面的包导出,从而导致问题。

我想提一个建议:

我看到pandora的plugin目录下有一个export.index文件,里面好像列出了所有导出类的列表。

我想ark的plugin的打包maven插件,是否可以在打包的时候,就根据export的package,把所有package下面的class导出到一个文件中。 这样在运行过程中查找类就可以精确匹配。

不知道这是不是一个好主意。

QilongZhang commented 5 years ago

hi @QilongZhang 我理解了这个设计原则。

但是,我觉得这种情况还是很常见的。 因为相同单位不同部门开发的插件,可能都会简单的设置 把“com.公司名” 下面的包导出,从而导致问题。

我想提一个建议:

我看到pandora的plugin目录下有一个export.index文件,里面好像列出了所有导出类的列表。

我想ark的plugin的打包maven插件,是否可以在打包的时候,就根据export的package,把所有package下面的class导出到一个文件中。 这样在运行过程中查找类就可以精确匹配。

不知道这是不是一个好主意。

之前 SOFAArk 借鉴了 Pandora 这个设计,有用户反馈 https://github.com/alipay/sofa-ark/issues/145 这个问题,这种方案并不适合 SOFAArk。 原因是 SOFAArk 沿用了 OSGi 的设计思路,所有类是动态懒加载的,而 Pandora 是提前加载好,index 方案不太适合 SOFAArk

QilongZhang commented 5 years ago

但是,我觉得这种情况还是很常见的。 因为相同单位不同部门开发的插件,可能都会简单的设置 把“com.公司名” 下面的包导出,从而导致问题。

"简单的设置" 其实是偷懒的行为,如果每个插件都这样设计,每个应用的运行时类加载都必须one by one 排查,OSGi 的规范以及我们内部最佳实践,plugin的导出导入类尽可能的范围精确,或者像上面回复的运行时进行规则校验

johnyannj commented 5 years ago

谢谢 @QilongZhang 您的耐心回复。

原因是 SOFAArk 沿用了 OSGi 的设计思路,所有类是动态懒加载的,而 Pandora 是提前加载好,index 方案不太适合 SOFAArk

使用index方案,类也不一定预先加载。也可以动态加载的吧。

之前 SOFAArk 借鉴了 Pandora 这个设计,有用户反馈 #145 这个问题

"简单的设置" 其实是偷懒的行为,如果每个插件都这样设计,每个应用的运行时类加载都必须one by one 排查,OSGi 的规范以及我们内部最佳实践,plugin的导出导入类尽可能的范围精确,或者像上面回复的运行时进行规则校验

我是觉得指定一个包名,可以覆盖自己的插件内所有要导出的类,是符合常人思维和逻辑的。

是不是class index+ package匹配 两个机制结合,是不是可以避免#145 的同时也解决了问题呢?

QilongZhang commented 5 years ago

使用单一的 package 匹配已经是可以解决这个问题的,index 对 sofaark 没有存在的价值了。

我是觉得指定一个包名,可以覆盖自己的插件内所有要导出的类,是符合常人思维和逻辑的。

没明白这句话的意思

johnyannj commented 5 years ago

我是觉得指定一个包名,可以覆盖自己的插件内所有要导出的类,是符合常人思维和逻辑的。

没描述准确,我的意思是,假设开发plugin的时候:

如果一个plugin要导出的类全部在 com.xxxx.a.b.c.d 下面。 他可以写 com.xxxx.a.b.c.d.*, 也可以写com.xxxx.* , 只要能覆盖自己plugin里要export的类就可以。都可以表示我这个plugin要导出哪些类。

这个已经是支持了。只是如果多个 Plugin 配置了相同的 package,只会委托给优先级高的 Plugin 加载。

QilongZhang commented 5 years ago

我是觉得指定一个包名,可以覆盖自己的插件内所有要导出的类,是符合常人思维和逻辑的。

没描述准确,我的意思是,假设开发plugin的时候:

如果一个plugin要导出的类全部在 com.xxxx.a.b.c.d 下面。 他可以写 com.xxxx.a.b.c.d., 也可以写com.xxxx. , 只要能覆盖自己plugin里要export的类就可以。都可以表示我这个plugin要导出哪些类。

这个已经是支持了。只是如果多个 Plugin 配置了相同的 package,只会委托给优先级高的 Plugin 加载。

这个已经支持了,只是如果多个 Plugin 导出相同的 Package, 只会委托给优先级高的 Plugin 加载。

johnyannj commented 5 years ago

这个已经支持了,只是如果多个 Plugin 导出相同的 Package, 只会委托给优先级高的 Plugin 加载。

我的意思就是 “如果多个 Plugin 导出相同的 Package”, 可不可以不只考虑优先级,因为低优先级的plugin里可能存在这个类, 高优先级的反而没这个类。

我们的讨论可能有点车轱辘循环了^_^

QilongZhang commented 5 years ago

这个已经支持了,只是如果多个 Plugin 导出相同的 Package, 只会委托给优先级高的 Plugin 加载。

我的意思就是 “如果多个 Plugin 导出相同的 Package”, 可不可以不只考虑优先级,因为低优先级的plugin里可能存在这个类, 高优先级的反而没这个类。

我们的讨论可能有点车轱辘循环了^_^

😄 这个应该不会支持,很有可能导致在一个package下面,一部分类由pluginA加载,一部分类由pluginB加载,对于排查问题是个灾难.. 这一点最好是遵循 OSGi 的规范。

johnyannj commented 5 years ago

很有可能导致在一个package下面,一部分类由pluginA加载,一部分类由pluginB加载,对于排查问题是个灾难

@QilongZhang 再次感谢您的耐心回复, 完全同意你说的这个问题。业务指定导出的包,确实不能重复。

此外,我还想提个另外的建议: 有关sofa-ark-plugin-maven-plugin的。 意思大体如下:

<exported>
    <!-- configure package-level exported class-->
    <packages>
        <package>com.alipay.sofa.ark.sample.common</package>
    </packages>

    <!-- configure class-level exported class -->
    <classes>
        <class>com.alipay.sofa.ark.sample.facade.SamplePluginService</class>
        **<package>com.alipay.sofa.www</package>**
    </classes>
</exported>

导出类这个地方,是否可以指定包名,然后maven插件帮这个包下类都列出来。 这样开发者就不用一个个的把类写出来了。

QilongZhang commented 5 years ago

导出类这个地方,是否可以指定包名,然后maven插件帮这个包下类都列出来。 这样开发者就不用一个个的把类写出来了。

额... 本身就支持包级别的导出

image

johnyannj commented 5 years ago

@QilongZhang 含义不一样,package导出是指运行的时候匹配用的。 我说这个是在打包的时候,把指定package下的类扫描出来,写到导出类列表里。

比如我有些类,因为第三方开源软件的限制,必须在org.springframework 下面。 但是org.springframework 这个包名又不能直接导出(和别人重复) 下面的类又很多,一个个的列出来又很麻烦。

QilongZhang commented 5 years ago

@QilongZhang 含义不一样,package导出是指运行的时候匹配用的。 我说这个是在打包的时候,把指定package下的类扫描出来,写到导出类列表里。

比如我有些类,因为第三方开源软件的限制,必须在org.springframework 下面。 但是org.springframework 这个包名又不能直接导出(和别人重复) 下面的类又很多,一个个的列出来又很麻烦。

扫描也还是会扫描你依赖的二方包中的类,并不支持扫描特定jar下面的package. 可以尽可能精确你需要导出的包范围,比如 org.springframework.xx 不一定非要配置到一个大的包范围中。