Skip to content
master
Go to file
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
 
 
 
 
 
 
 
 

README.md

Land

Build Status Coverage Status GitHub issues
Dependency Status License

🏁 概述

👉 一个简单的基于ClassLoader用于依赖隔离的容器实现。
# 在Java中依赖主要是Jar

依赖容器自然涉及下面的问题:

  • 可以从多处加载类,并分配不同的ClassLoader
  • ClassLoader之间有继承关系
    ClassLoader的继承关系会是一个树
  • 类加载会在上下级ClassLoader之间有委托关系,如:
    • 是否允许在上级ClassLoader中查找类。
      即是否 委托
    • 允许在上级ClassLoader查找哪些类/包。
      即可以配置 委托 的粒度。
    • 只允许在某级ClassLoader查找哪些类/包,会忽略这级ClassLoader的下级ClassLoader中这些类/包,不允许子ClassLoader
      即必须 委托

🔧 功能

1. ClassLoader委托关系的完备配置

父子ClassLoader委托

完备委托关系可以先分析只有父子2层ClassLoader间委托关系的情况。

某个类的加载在两层父子ClassLoader间委托关系,按是否加载排列组合一共有4种情况:

  • 父不加载,子不加载【00】
    可以用来显式禁止某些类的加载。
    实际应用中应该 很少 会用到。
  • 父不加载,子加载【01】
    子自理,父里即使包含了相同的类也不会污染子。实际场景:
    • 用来Tomcat容器自用Lib,不会影响到的Web应用。
  • 父加载,子不加载【10】
    一定使用的父的类。实际场景:
    • Tomcat容器的Servlet API,不允许被Web应用改写。
  • 父加载,子加载【11】
    两者可以加载的情况下,按谁优先分成2个Case:
    • 父优先。【Parent-Child
      即是Java缺省的委托策略,代理模式(Delegation Mode)。
      这个委托策略可以保证Java核心库的类型优先加载,Java核心库的类的加载工作由引导类加载器来统一完成,保证了Java应用所使用的都是同一个版本的Java核心库的类,是互相兼容的。
    • 子优先。【Child-Parent
      这种委托关系比较复杂,有引起类版本混乱的风险!💣
      实际应用中应该 避免 这种委托关系。 🙅

ℹ️
关于子优先【Child-Parent】类版本混乱的风险的细节原因看了后面参考资料就清楚了,这里只说一个简单例子:
子里有类Wheel;父里有类CarWheel;类Car引用了类Wheel
子加载类Car里通过实际是父来加载(子中没有这个类),返回的Car所引用Wheel是用CarClassLoader即父来加载。
子中直接使用Wheel时,由子来加载(子里有Wheel类)。
结果Car引用的类Wheel和子直接使用的类WheelClassLoader不同,即类型不兼容,看起来正确的赋值会抛出的ClassCastException

上面【11】的情况分成2个子Case,合起来一共有5种情况。

委托关系可以统一描述成:

  1. None
  2. Child-Only
  3. Parent-Only
  4. Parent-Child
  5. Child-Parent

按上面说明的2层委托关系约定,嵌套推广即可得到 包含 任意层ClassLoader的完备委托关系。

兄弟ClassLoader委托

父子ClassLoader由于树状的单继承关系,委托关系比较单一。 要实现复杂的代理关系,兄弟ClassLoader之间代理可以简化。

举个场景,多个中间件如RPCMessage等,要需要把部分类代理给应用ClassLoader,如果就使用父子代理,结果会是这样:

System ClassLoader
    |
    V
RPC ClassLoader
    |
    V
Message ClassLoader
    |
    V
App ClassLoader

上面问题是,RPC ClassLoaderMessage ClassLoader之间的父子关系不符合实际关系(RPC ClassLoaderMessage ClassLoader之间并不需要父子代理)。

更合理些的代理关系是:

                  System ClassLoader
                /         |         \
              /           |          \
            V             V           V
RPC ClassLoader -> App ClassLoader <- Message ClassLoader

RPC ClassLoaderMessage ClassLoader作为App ClassLoader的兄弟ClassLoader并代理。

2. 常用类加载方式

  • 加载本地类目录或Jar文件
  • 加载本地有类目录或Jar文件的目录
  • 加载网络上的类
    这个功能应该很少使用 😜 ,为了功能完整而说明。
  • 加密类工具/加载加密的类
    这个功能应该很少使用 😝 ,为了功能完整而说明。

🎨 使用场景

  1. 在一个JVM中部署多个应用,但应用依赖不互相影响。
    这样是提高 系统利用率 的一种方式。
  2. 把平台级的二方库从应用中隔离出来,由架构部门统一升级。这样做的原因是:
    • 平台级二方库如果有Bug影响面广,有统一的升级的需求。
    • 平台级二方库升级使用面广,升级困难。

ℹ️
上面的部署方式中,依赖容器的引入对于应用的开发应该是 透明 的。

🍺 目标

  • 给出类加载委托情况的完备说明
  • 给出类加载委托规则的规范描述
  • 给出类加载委托规则的规范描述的自己的一个描述格式
    对于这个项目会优先使用Properties来描述,简单够用。
  • 说明JavaClassLoader的用途和限制
  • 给出ClassLoader使用和实现的原则
  • ClassLoader使用和实现容易出错的地方
  • 整理出使用了ClassLoader的常见框架
  • 说明这些框架中ClassLoader的实现方法及其使用契约
  • 给出ClassLoader实现方法及其使用契约的最佳实践

📢 进阶目标

  • Web容器集成
  • 实现OSGi规范
    这个也可以用来验证实现是否面向编程友好

📚 相关资料

🔬 官方资料

ClassLoader

Permission

🔖 二手资料

ClassLoader

ClassLoader实际应用

安全

ClassLoader Memory Leak

You can’t perform that action at this time.