Open soudegesu opened 6 years ago
そもそも、 --module-path
は今回以下のようにして定義している。
bootRun {
doFirst {
jvmArgs += [
"--module-path", classpath.asPath,
"--add-modules", "java.sql",
"--module", "soudegesu.springboot.jdknine.main.demo/soudegesu.springboot.jdknine.main.demo.DemoApplication"
]
classpath = files()
}
}
ModuleLayer#boot
にbreak pointを設定し、 IntelliJ の bootRun
を実行する
System.bootLayer
に何が設定されているかを確認する
public static ModuleLayer boot() {
return System.bootLayer;
}
bootLayer
内に modules
がたくさん生成されている
さらにその中も modules
でネストされているようだ
sun.launcher.LauncherHelper#loadModuleMainClass
で引数に指定された --module
(今回の場合 soudegesu.springboot.jdknine.main.demo/soudegesu.springboot.jdknine.main.demo.DemoApplication
) を boot layer
の中からfindしている
// main module is in the boot layer
ModuleLayer layer = ModuleLayer.boot();
Optional<Module> om = layer.findModule(mainModule);
if (!om.isPresent()) {
// should not happen
throw new InternalError("Module " + mainModule + " not in boot Layer");
}
Module m = om.get();
Module
と ModuleLayer
と ModuleDescripter
の関係性を理解したい。あと、ClassLoader。
open moduleで設定していたので、こんな感じになる。
ModuleDescripterには module-info.java
で宣言していた情報が格納されている。
requires
もこの通り.
automatic module だとこんな感じ。
java.base
は必ず requires
されるのか。
今の所、 ModuleLayer はオブジェクトのアドレスが全部いっしょだなぁ。
ModuleLayerに登録されているModule全てが参照されているわけではないっぽい
http://d.hatena.ne.jp/miyakawa_taku/20171108/1510145001
を参考に ModuleLayerの各メソッドにブレークポイントを貼ったが、 defineModule
で止まらないなぁ。
javadocにこんな記載が https://docs.oracle.com/javase/jp/9/docs/api/java/lang/ModuleLayer.html
レイヤー内の各Moduleは、そのModuleDescriptorで記述されたパッケージをexportsとopensが作成するように作成されます。 (パッケージがすべてのモジュールではなくターゲット・モジュールのセットにエクスポートされる)は次のようにレイヤーを作成するときに修飾されたエクスポートです:
モジュールXがパッケージをYにエクスポートし、ランタイムModule XがModule Yを読み取る場合、パッケージはModule Y (これはXと同じレイヤーまたは親レイヤーにあります)にエクスポートされます。
モジュールXがパッケージをYにエクスポートし、ランタイムModule XがYを読み取らない場合、Yは、findModuleを呼び出してレイヤーまたはその親レイヤー内のモジュールを検索するかのように配置されます。 Yが見つかった場合、パッケージはYのインスタンスにエクスポートされます。 Yが見つからない場合、修飾されたエクスポートは無視されます。
Automcatic Module に関しても以下のような記載が
Configurationを作成するときと同様に、automaticモジュールは、レイヤーを作成するときに特別な処理を受け取ります。 Java仮想マシン内で、Java仮想マシン内の無名の Moduleをすべて読み取るModuleとして、自動モジュールが作成されます。
System#initPhase2 -> ModuleBootstrap#boot がmodule systemの初期化処理
処理中にこんなものあある
// --module-path option specified to the launcher
ModuleFinder appModulePath = createModulePathFinder("jdk.module.path");
-m
オプションで モジュール指定してアプリケーションを起動すると、
そのモジュールが root module
にaddされるようだ。
// launcher -m option to specify the main/initial module
String mainModule = System.getProperty("jdk.module.main");
if (mainModule != null)
roots.add(mainModule);
引数に指定された --add-module
もroot moduleに追加されるようだ
for (String mod: getExtraAddModules()) {
switch (mod) {
case ALL_DEFAULT:
addAllDefaultModules = true;
break;
case ALL_SYSTEM:
addAllSystemModules = true;
break;
case ALL_MODULE_PATH:
addAllApplicationModules = true;
break;
default :
roots.add(mod);
}
}
Configuration を作ってあられる
// run the resolver to create the configuration
Configuration cf = SharedSecrets.getJavaLangModuleAccess()
.resolveAndBind(finder,
roots,
needPostResolutionChecks,
traceOutput);
#resolveAndBind
はこんな感じ
/**
* Resolves a collection of root modules, with service binding, and with
* the empty configuration as its parent. The consistency checks
* are optionally run.
*
* This method is used to create the configuration for the boot layer.
*/
static Configuration resolveAndBind(ModuleFinder finder,
Collection<String> roots,
boolean check,
PrintStream traceOutput)
{
List<Configuration> parents = List.of(empty());
Resolver resolver = new Resolver(finder, parents, ModuleFinder.of(), traceOutput);
resolver.resolve(roots).bind();
return new Configuration(parents, resolver, check);
}
Resolver#resolve
の処理の中にこんなものがある
// if the module is an automatic module then all automatic
// modules need to be resolved
if (descriptor.isAutomatic() && !haveAllAutomaticModules) {
addFoundAutomaticModules().forEach(mref -> {
ModuleDescriptor other = mref.descriptor();
q.offer(other);
if (isTracing()) {
trace("%s requires %s", descriptor.name(), nameAndInfo(mref));
}
});
haveAllAutomaticModules = true;
}
bootLoaderは全てのモジュールが入っているぽい
/**
* Load/register the modules to the built-in class loaders.
*/
private static void loadModules(Configuration cf,
Function<String, ClassLoader> clf) {
for (ResolvedModule resolvedModule : cf.modules()) {
ModuleReference mref = resolvedModule.reference();
String name = resolvedModule.name();
ClassLoader loader = clf.apply(name);
if (loader == null) {
// skip java.base as it is already loaded
if (!name.equals(JAVA_BASE)) {
BootLoader.loadModule(mref);
}
} else if (loader instanceof BuiltinClassLoader) {
((BuiltinClassLoader) loader).loadModule(mref);
}
}
}
/**
* Register a module this class loader. This has the effect of making the
* types in the module visible.
*/
public void loadModule(ModuleReference mref) {
String mn = mref.descriptor().name();
if (nameToModule.putIfAbsent(mn, mref) != null) {
throw new InternalError(mn + " already defined to this loader");
}
LoadedModule loadedModule = new LoadedModule(this, mref);
for (String pn : mref.descriptor().packages()) {
LoadedModule other = packageToModule.putIfAbsent(pn, loadedModule);
if (other != null) {
throw new InternalError(pn + " in modules " + mn + " and "
+ other.mref().descriptor().name());
}
}
// clear resources cache if VM is already initialized
if (VM.isModuleSystemInited() && resourceCache != null) {
resourceCache = null;
}
}
java9の仕様上
ModuleLayer
内でのパッケージの重複は認められない、っていうのはどういうことか、を調べてみるメモ