维护一个局部的类加载器(localLoader)。
PluginClassLoader遵循双亲委派,在类加载过程中先委派SermantClassLoader加载Sermant的核心类,再通过自身加载插件类,当需要使用宿主服务的类时,则会委托局部类加载器(其Parent可以是任何类加载器,不局限于图中所指示)进行加载。用于让字节码增强的切面逻辑(Sermant拦截器)可以获取到宿主服务所使用的类,这有利于服务治理场景,其逻辑如下图所示:
通过重写类加载器loadClass逻辑,在执行Sermant拦截器时,配置一个局部的类加载环境,让Sermant拦截器中的逻辑可以顺利的使用宿主服务加载的类,这样开发服务治理插件时无需通过反射获取宿主服务的类,从而提升服务治理能力的开发效率和最终运行时的性能,同时还避免了宿主服务和服务治理插件的类冲突。
(代码实现可以在开源仓库进行查看:)
3) 实战效果如何
因接入JavaAgent而导致的依赖冲突、类冲突问题乃是业界通病,但如果有Sermant的类加载机制加持,该问题则可从根源避免,不再让广大JavaAgent的使用者和开发者深受其害!
《拜托,别在 agent 中依赖 fastjson 了》所述案例,是一个因JavaAgent而产生的依赖冲突问题的典型场景,其应用通过AppClassLoader加载到了Agent中fastjson的类FastJsonHttpMessageConverter, 该类依赖spring-web.jar的类GenericHttpMessageConverter,但由于AppClassLoader的搜索路径中并没有spring-web.jar(fastjson通过provide方式引入),最终加载类失败。
但如基于Sermant开发则不会产生该问题,基于Sermant开发JavaAgent和Spring应用一起运行时的类隔离架构如下:
在此类加载器的结构下,有两个关键的不同:
- 由于Sermant改变了类加载的结构,通过Agent引入的fastjson已不在AppClassLoader的搜索路径中,因此Agent中的FastJsonHttpMessageConverter类不再会被Spring应用通过AppClassLoader加载到,从根源上避免了文中所触发的类冲突问题。
- 当运行时若Agent需要使用spring-web的类GenericHttpMessageConverter时,则可通过Sermant提供的局部类加载环境成功通过LaunchedUrlClassloader成功从Spring应用中获取。
正是因为此两点差异,让基于Sermant开发的能力可以在和应用之间进行类隔离,避免通过JavaAgent引入类冲突问题,同时可以在运行时使用应用所引入的类。
四、总结
Sermant是基于Java字节码增强技术的无代理服务网格,其利用Java字节码增强技术为宿主应用程序提供服务治理功能。因深知JavaAgent场景中类冲突问题会造成的影响,Sermant在设计之初便为此规划了全面的类隔离架构。经历多次迭代,如今Sermant的类隔离架构已可以轻松的应对各种复杂的类加载环境。
除了保证类隔离,Sermant作为服务网格需要重点关注自身的服务治理能力对宿主服务带来的性能影响,所以也通过独有设计避免因为过度隔离带来的性能损耗。同时Sermant还在构建开放的服务治理插件开发生态,并提供高效的服务治理能力开发框架。在类隔离设计时也考虑到了易用性、开发效率提升等方面的问题。并未因为类隔离机制的存在,而降低开发的效率,增大学习曲线的陡峭程度。
Sermant 作为专注于服务治理领域的字节码增强框架,致力于提供高性能、可扩展、易接入、功能丰富的服务治理体验,并会在每个版本中做好性能、功能、体验的看护,广泛欢迎大家的加入。
点击关注,第一时间了解华为云新鲜技术~