UnifiedClassLoader3

最初にUnifiedClassLoader3#loadClass()が呼ばれるのはorg.jboss.system.server.ServerInfoをロードするとき

UnifiedClassLoader3(RepositoryClassLoader).loadClass(String, boolean) line: 357
UnifiedLoaderRepository3.loadClass(String, boolean, ClassLoader) line: 188
UnifiedLoaderRepository3.loadClass(String) line: 572
MBeanServerImpl.instantiate(String, ClassLoader, Object[], String[]) line: 1192
MBeanServerImpl.instantiate(String) line: 233
ServerImpl.createMBean(String, String) line: 480
ServerImpl.doStart() line: 387
ServerImpl.start() line: 315
Main.boot(String[]) line: 195
Main$1.run() line: 463
Thread.run() line: 534

MBeanServerImplはフィールドとしてclassLoaderRepositoryを持っている(デフォルトはUnifiedLoaderRepository3)ので、クラスロードはそこを経由する。

UnifiedLoaderRepository3#loadClass(String)は

    • classLoadersのひとつめのloadClass()を呼ぶ
    • 見つからなければ、TCLのloadClass()
    • 見つからなければ、getNativeClassForName()
    • 見つからなければ、ClassNotFoundException

UnifiedClassLoader3#loadClass(String, boolean)は

UnifiedLoaderRepository3のgetCachedClass()を呼んでキャッシュを探す
 → キャッシュはMapに単純に入っている(もちろん各クラスはdefineしたClassLoaderに紐づいているハズ)
見つからなければ、synchronized loadClassImpl()
 → クラスロード用ロックを取得*1(Cuncurrentとか使っている。LoadMgr3はユーティリティ)
   LoadMgr3.beginLoadTask()でロード開始
    → UnifiedLoaderRepository3#loadClassFromCache()でまたキャッシュを探す
      UnifiedLoaderRepository3のpackagesMap*2からパッケージ名(org.jboss.system.server)に対応した、クラスローダのSetを返す
      Setがあった…そのクラスローダにクラスを探させるタスクをスケジュールする
      Setは無い…自分で探せ UnifiedClassLoader3#loadClassLocally()
       → そのクラスがブラックリストにあれば即ClassNotFound
         super.loadClass() … 普通にURLClassLoaderとして探す
         見つからなければブラックリスト
      キャッシュclassesに追加
      「クラスローダ-ロードしたクラス」マップのloaderToClassesMapを更新


WARをデプロイして実験

MainDeployerがデプロイする:org.jboss.web.tomcat.tc5.Tomcat5、org.jboss.web.tomcat.tc5.TomcatDeployerに委譲
デプロイ時にもいろいろロードするけど、WAR内のクラス(test.web.TestServlet)はロードされない

アクセス時にロードしようとする

UnifiedClassLoader3(RepositoryClassLoader).loadClass(String, boolean) line: 377
UnifiedClassLoader3(ClassLoader).loadClass(String) line: 235
StandardWrapper.isContainerProvidedServlet(String) line: 1532
StandardWrapper.loadServlet() line: 991
StandardWrapper.allocate() line: 750
StandardWrapperValve.invoke(Request, Response) line: 130
StandardContextValve.invoke(Request, Response) line: 178
CustomPrincipalValve.invoke(Request, Response) line: 39
SecurityAssociationValve.invoke(Request, Response) line: 153
JaccContextValve.invoke(Request, Response) line: 59
StandardHostValve.invoke(Request, Response) line: 126
ErrorReportValve.invoke(Request, Response) line: 105
StandardEngineValve.invoke(Request, Response) line: 107
CoyoteAdapter.service(Request, Response) line: 148
Http11Processor.process(InputStream, OutputStream) line: 856
Http11Protocol$Http11ConnectionHandler.processConnection(TcpConnection, Object[]) line: 744
PoolTcpEndpoint.processSocket(Socket, TcpConnection, Object[]) line: 527
MasterSlaveWorkerThread.run() line: 112
ThreadWithAttributes(Thread).run() line: 534

test.web.TestServletが検索されるがClassNotFoundとなり、以降検索されずじまい…なのに正常にサーブレットは処理された。。。??

4.0.2から
jbossweb-tomcat55.sar/META-INF/jboss-service.xmlでUseJBossWebLoader=falseだから、Tomcat側でロードするんだった!

…UseJBossWebLoader=trueにしたらtest.web.TestServletの検索に成功!

*1:UnifiedClassLoader3はUnifiedClassLoaderのマルチスレッド対応と説明されているが、スレッド対応のコードは親のRepositoryClassLoaderに入っているよ。なんか継承関係が整理されてない気がするなあ

*2:packegeMapは新規にUCLが生成されるときにClassLoaderUtils#updatePackageMap()により検索パスを解析して更新される