-
Notifications
You must be signed in to change notification settings - Fork 669
/
Copy pathModuleLayer.java
1003 lines (906 loc) · 44.3 KB
/
ModuleLayer.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang;
import java.lang.module.Configuration;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ResolvedModule;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.internal.loader.ClassLoaderValue;
import jdk.internal.loader.Loader;
import jdk.internal.loader.LoaderPool;
import jdk.internal.module.ServicesCatalog;
import sun.security.util.SecurityConstants;
/**
* A layer of modules in the Java virtual machine.
*
* <p> A layer is created from a graph of modules in a {@link Configuration}
* and a function that maps each module to a {@link ClassLoader}.
* Creating a layer informs the Java virtual machine about the classes that
* may be loaded from the modules so that the Java virtual machine knows which
* module that each class is a member of. </p>
*
* <p> Creating a layer creates a {@link Module} object for each {@link
* ResolvedModule} in the configuration. For each resolved module that is
* {@link ResolvedModule#reads() read}, the {@code Module} {@link
* Module#canRead reads} the corresponding run-time {@code Module}, which may
* be in the same layer or a {@link #parents() parent} layer. </p>
*
* <p> The {@link #defineModulesWithOneLoader defineModulesWithOneLoader} and
* {@link #defineModulesWithManyLoaders defineModulesWithManyLoaders} methods
* provide convenient ways to create a module layer where all modules are
* mapped to a single class loader or where each module is mapped to its own
* class loader. The {@link #defineModules defineModules} method is for more
* advanced cases where modules are mapped to custom class loaders by means of
* a function specified to the method. Each of these methods has an instance
* and static variant. The instance methods create a layer with the receiver
* as the parent layer. The static methods are for more advanced cases where
* there can be more than one parent layer or where a {@link
* ModuleLayer.Controller Controller} is needed to control modules in the layer
* </p>
*
* <p> A Java virtual machine has at least one non-empty layer, the {@link
* #boot() boot} layer, that is created when the Java virtual machine is
* started. The boot layer contains module {@code java.base} and is the only
* layer in the Java virtual machine with a module named "{@code java.base}".
* The modules in the boot layer are mapped to the bootstrap class loader and
* other class loaders that are <a href="ClassLoader.html#builtinLoaders">
* built-in</a> into the Java virtual machine. The boot layer will often be
* the {@link #parents() parent} when creating additional layers. </p>
*
* <p> Each {@code Module} in a layer is created so that it {@link
* Module#isExported(String) exports} and {@link Module#isOpen(String) opens}
* the packages described by its {@link ModuleDescriptor}. Qualified exports
* (where a package is exported to a set of target modules rather than all
* modules) are reified when creating the layer as follows: </p>
* <ul>
* <li> If module {@code X} exports a package to {@code Y}, and if the
* runtime {@code Module} {@code X} reads {@code Module} {@code Y}, then
* the package is exported to {@code Module} {@code Y} (which may be in
* the same layer as {@code X} or a parent layer). </li>
*
* <li> If module {@code X} exports a package to {@code Y}, and if the
* runtime {@code Module} {@code X} does not read {@code Y} then target
* {@code Y} is located as if by invoking {@link #findModule(String)
* findModule} to find the module in the layer or its parent layers. If
* {@code Y} is found then the package is exported to the instance of
* {@code Y} that was found. If {@code Y} is not found then the qualified
* export is ignored. </li>
* </ul>
*
* <p> Qualified opens are handled in same way as qualified exports. </p>
*
* <p> As when creating a {@code Configuration},
* {@link ModuleDescriptor#isAutomatic() automatic} modules receive special
* treatment when creating a layer. An automatic module is created in the
* Java virtual machine as a {@code Module} that reads every unnamed {@code
* Module} in the Java virtual machine. </p>
*
* <p> Unless otherwise specified, passing a {@code null} argument to a method
* in this class causes a {@link NullPointerException NullPointerException} to
* be thrown. </p>
*
* <h3> Example usage: </h3>
*
* <p> This example creates a configuration by resolving a module named
* "{@code myapp}" with the configuration for the boot layer as the parent. It
* then creates a new layer with the modules in this configuration. All modules
* are defined to the same class loader. </p>
*
* <pre>{@code
* ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
*
* ModuleLayer parent = ModuleLayer.boot();
*
* Configuration cf = parent.configuration().resolve(finder, ModuleFinder.of(), Set.of("myapp"));
*
* ClassLoader scl = ClassLoader.getSystemClassLoader();
*
* ModuleLayer layer = parent.defineModulesWithOneLoader(cf, scl);
*
* Class<?> c = layer.findLoader("myapp").loadClass("app.Main");
* }</pre>
*
* @since 9
* @spec JPMS
* @see Module#getLayer()
*/
// 模块层,包含了模块图
public final class ModuleLayer {
// 空模块层,内部包含一个空模块图,该模块层通常作为Boot Layer的父模块层(最底下的一个模块层)
private static final ModuleLayer EMPTY_LAYER = new ModuleLayer(Configuration.empty(), List.of(), null); // the empty layer
// 模块图
private final Configuration configuration; // the configuration from which this layer was created
// 父模块层
private final List<ModuleLayer> parents; // parent layers, empty in the case of the empty layer
// 模块名到模块实例的映射
private final Map<String, Module> nameToModule; // maps module name to jlr.Module
// 当前模块层及其父模块层的集合
private volatile List<ModuleLayer> allLayers;
// 当前模块层内所有模块
private volatile Set<Module> modules;
// 当前模块层的服务目录(包含所有模块内的所有提供的服务)
private volatile ServicesCatalog servicesCatalog;
/*
* 模块层CLV,由所有模块层对象共享
*
* 该CLV映射的值是其所在类加载器参与定义过的所有模块层
*/
private static final ClassLoaderValue<List<ModuleLayer>> CLV = new ClassLoaderValue<>();
/*▼ 构造方法 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Creates a new module layer from the modules in the given configuration.
*/
private ModuleLayer(Configuration configuration, List<ModuleLayer> parents, Function<String, ClassLoader> fn) {
this.configuration = configuration;
this.parents = parents; // no need to do defensive copy
Map<String, Module> map;
// 如果不存在父模块层(Boot Layer存在一个EMPTY_LAYER的父模块层)
if(parents.isEmpty()) {
map = Collections.emptyMap();
} else {
// 定义指定模块图中的所有模块,返回模块名到模块实例的映射
map = Module.defineModules(configuration, fn, this);
}
this.nameToModule = map; // no need to do defensive copy
}
/*▲ 构造方法 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 定义模块层 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Creates a new module layer, with this layer as its parent, by defining the
* modules in the given {@code Configuration} to the Java virtual machine.
* Each module is mapped, by name, to its class loader by means of the
* given function. This method works exactly as specified by the static
* {@link #defineModules(Configuration, List, Function) defineModules}
* method when invoked with this layer as the parent. In other words, if
* this layer is {@code thisLayer} then this method is equivalent to
* invoking:
* <pre> {@code
* ModuleLayer.defineModules(cf, List.of(thisLayer), clf).layer();
* }</pre>
*
* @param cf The configuration for the layer
* @param clf The function to map a module name to a class loader
*
* @return The newly created layer
*
* @throws IllegalArgumentException If the given configuration has more than one parent or the parent
* of the configuration is not the configuration for this layer
* @throws LayerInstantiationException If the layer cannot be created for any of the reasons specified
* by the static {@code defineModules} method
* @throws SecurityException If {@code RuntimePermission("getClassLoader")} is denied by
* the security manager
*/
/*
* 构造新的模块层,父模块层就是当前模块层
*
* cf : 模块图
* clf : 加载指定模块时用到的类加载器集合
*/
public ModuleLayer defineModules(Configuration cf, Function<String, ClassLoader> clf) {
return defineModules(cf, List.of(this), clf).layer();
}
/**
* Creates a new module layer by defining the modules in the given {@code
* Configuration} to the Java virtual machine. The given function maps each
* module in the configuration, by name, to a class loader. Creating the
* layer informs the Java virtual machine about the classes that may be
* loaded so that the Java virtual machine knows which module that each
* class is a member of.
*
* <p> The class loader delegation implemented by the class loaders must
* respect module readability. The class loaders should be
* {@link ClassLoader#registerAsParallelCapable parallel-capable} so as to
* avoid deadlocks during class loading. In addition, the entity creating
* a new layer with this method should arrange that the class loaders be
* ready to load from these modules before there are any attempts to load
* classes or resources. </p>
*
* <p> Creating a layer can fail for the following reasons: </p>
*
* <ul>
*
* <li><p> Two or more modules with the same package are mapped to the
* same class loader. </p></li>
*
* <li><p> A module is mapped to a class loader that already has a
* module of the same name defined to it. </p></li>
*
* <li><p> A module is mapped to a class loader that has already
* defined types in any of the packages in the module. </p></li>
*
* </ul>
*
* <p> In addition, a layer cannot be created if the configuration contains
* a module named "{@code java.base}", a configuration contains a module
* with a package named "{@code java}" or a package name starting with
* "{@code java.}", or the function to map a module name to a class loader
* returns {@code null} or the {@linkplain ClassLoader#getPlatformClassLoader()
* platform class loader}. </p>
*
* <p> If the function to map a module name to class loader throws an error
* or runtime exception then it is propagated to the caller of this method.
* </p>
*
* @param cf The configuration for the layer
* @param parentLayers The list of parent layers in search order
* @param clf The function to map a module name to a class loader
*
* @return A controller that controls the newly created layer
*
* @throws IllegalArgumentException If the parent(s) of the given configuration do not match the
* configuration of the parent layers, including order
* @throws LayerInstantiationException If creating the layer fails for any of the reasons listed above
* @throws SecurityException If {@code RuntimePermission("getClassLoader")} is denied by
* the security manager
* @apiNote It is implementation specific as to whether creating a layer
* with this method is an atomic operation or not. Consequentially it is
* possible for this method to fail with some modules, but not all, defined
* to the Java virtual machine.
*/
/*
* 构造新的模块层
*
* cf : 模块图
* parentLayers: 父模块层
* clf : 加载指定模块时用到的类加载器集合
*/
public static Controller defineModules(Configuration cf, List<ModuleLayer> parentLayers, Function<String, ClassLoader> clf) {
List<ModuleLayer> parents = new ArrayList<>(parentLayers);
checkConfiguration(cf, parents);
Objects.requireNonNull(clf);
checkGetClassLoaderPermission();
// The boot layer is checked during module system initialization
if(boot() != null) {
checkForDuplicatePkgs(cf, clf);
}
try {
ModuleLayer layer = new ModuleLayer(cf, parents, clf);
return new Controller(layer);
} catch(IllegalArgumentException | IllegalStateException e) {
throw new LayerInstantiationException(e.getMessage());
}
}
/**
* Creates a new module layer, with this layer as its parent, by defining the
* modules in the given {@code Configuration} to the Java virtual machine.
* This method creates one class loader and defines all modules to that
* class loader. The {@link ClassLoader#getParent() parent} of each class
* loader is the given parent class loader. This method works exactly as
* specified by the static {@link
* #defineModulesWithOneLoader(Configuration, List, ClassLoader)
* defineModulesWithOneLoader} method when invoked with this layer as the
* parent. In other words, if this layer is {@code thisLayer} then this
* method is equivalent to invoking:
* <pre> {@code
* ModuleLayer.defineModulesWithOneLoader(cf, List.of(thisLayer), parentLoader).layer();
* }</pre>
*
* @param cf The configuration for the layer
* @param parentLoader The parent class loader for the class loader created by this
* method; may be {@code null} for the bootstrap class loader
*
* @return The newly created layer
*
* @throws IllegalArgumentException If the given configuration has more than one parent or the parent
* of the configuration is not the configuration for this layer
* @throws LayerInstantiationException If the layer cannot be created for any of the reasons specified
* by the static {@code defineModulesWithOneLoader} method
* @throws SecurityException If {@code RuntimePermission("createClassLoader")} or
* {@code RuntimePermission("getClassLoader")} is denied by
* the security manager
* @see #findLoader
*/
/*
* 构造新的模块层,父模块层就是当前模块层
*
* cf : 模块图
* parentLoader: 所有模块会用到一个模块类加载器,该类加载器的父级类加载器是parentLoader
*/
public ModuleLayer defineModulesWithOneLoader(Configuration cf, ClassLoader parentLoader) {
return defineModulesWithOneLoader(cf, List.of(this), parentLoader).layer();
}
/**
* Creates a new module layer by defining the modules in the given {@code
* Configuration} to the Java virtual machine. This method creates one
* class loader and defines all modules to that class loader.
*
* <p> The class loader created by this method implements <em>direct
* delegation</em> when loading classes from modules. If the {@link
* ClassLoader#loadClass(String, boolean) loadClass} method is invoked to
* load a class then it uses the package name of the class to map it to a
* module. This may be a module in this layer and hence defined to the same
* class loader. It may be a package in a module in a parent layer that is
* exported to one or more of the modules in this layer. The class
* loader delegates to the class loader of the module, throwing {@code
* ClassNotFoundException} if not found by that class loader.
* When {@code loadClass} is invoked to load classes that do not map to a
* module then it delegates to the parent class loader. </p>
*
* <p> The class loader created by this method locates resources
* ({@link ClassLoader#getResource(String) getResource}, {@link
* ClassLoader#getResources(String) getResources}, and other resource
* methods) in all modules in the layer before searching the parent class
* loader. </p>
*
* <p> Attempting to create a layer with all modules defined to the same
* class loader can fail for the following reasons:
*
* <ul>
*
* <li><p> <em>Overlapping packages</em>: Two or more modules in the
* configuration have the same package. </p></li>
*
* <li><p> <em>Split delegation</em>: The resulting class loader would
* need to delegate to more than one class loader in order to load
* classes in a specific package. </p></li>
*
* </ul>
*
* <p> In addition, a layer cannot be created if the configuration contains
* a module named "{@code java.base}", or a module contains a package named
* "{@code java}" or a package with a name starting with "{@code java.}". </p>
*
* <p> If there is a security manager then the class loader created by
* this method will load classes and resources with privileges that are
* restricted by the calling context of this method. </p>
*
* @param cf The configuration for the layer
* @param parentLayers The list of parent layers in search order
* @param parentLoader The parent class loader for the class loader created by this
* method; may be {@code null} for the bootstrap class loader
*
* @return A controller that controls the newly created layer
*
* @throws IllegalArgumentException If the parent(s) of the given configuration do not match the
* configuration of the parent layers, including order
* @throws LayerInstantiationException If all modules cannot be defined to the same class loader for any
* of the reasons listed above
* @throws SecurityException If {@code RuntimePermission("createClassLoader")} or
* {@code RuntimePermission("getClassLoader")} is denied by
* the security manager
* @see #findLoader
*/
/*
* 构造新的模块层
*
* cf : 模块图
* parentLayers: 父模块层
* parentLoader: 所有模块会用到一个模块类加载器,该类加载器的父级类加载器是parentLoader
*/
public static Controller defineModulesWithOneLoader(Configuration cf, List<ModuleLayer> parentLayers, ClassLoader parentLoader) {
List<ModuleLayer> parents = new ArrayList<>(parentLayers);
checkConfiguration(cf, parents);
checkCreateClassLoaderPermission();
checkGetClassLoaderPermission();
try {
// 获取模块图中的模块集
Set<ResolvedModule> modules = cf.modules();
// 用parent作为父级类加载器,为指定模块集合中的所有模块构造一个模块类加载器
Loader loader = new Loader(modules, parentLoader);
// 初始化依赖包到类加载器的映射,参见字段remotePackageToLoader的说明
loader.initRemotePackageMap(cf, parents);
ModuleLayer layer = new ModuleLayer(cf, parents, mn -> loader);
return new Controller(layer);
} catch(IllegalArgumentException | IllegalStateException e) {
throw new LayerInstantiationException(e.getMessage());
}
}
/**
* Creates a new module layer, with this layer as its parent, by defining the
* modules in the given {@code Configuration} to the Java virtual machine.
* Each module is defined to its own {@link ClassLoader} created by this
* method. The {@link ClassLoader#getParent() parent} of each class loader
* is the given parent class loader. This method works exactly as specified
* by the static {@link
* #defineModulesWithManyLoaders(Configuration, List, ClassLoader)
* defineModulesWithManyLoaders} method when invoked with this layer as the
* parent. In other words, if this layer is {@code thisLayer} then this
* method is equivalent to invoking:
* <pre> {@code
* ModuleLayer.defineModulesWithManyLoaders(cf, List.of(thisLayer), parentLoader).layer();
* }</pre>
*
* @param cf The configuration for the layer
* @param parentLoader The parent class loader for each of the class loaders created by
* this method; may be {@code null} for the bootstrap class loader
*
* @return The newly created layer
*
* @throws IllegalArgumentException If the given configuration has more than one parent or the parent
* of the configuration is not the configuration for this layer
* @throws LayerInstantiationException If the layer cannot be created for any of the reasons specified
* by the static {@code defineModulesWithManyLoaders} method
* @throws SecurityException If {@code RuntimePermission("createClassLoader")} or
* {@code RuntimePermission("getClassLoader")} is denied by
* the security manager
* @see #findLoader
*/
/*
* 构造新的模块层,父模块层就是当前模块层
*
* cf : 模块图
* parentLoader: 所有模块类加载器的父级类加载器(不同的模块使用不同的类加载器)
*/
public ModuleLayer defineModulesWithManyLoaders(Configuration cf, ClassLoader parentLoader) {
return defineModulesWithManyLoaders(cf, List.of(this), parentLoader).layer();
}
/**
* Creates a new module layer by defining the modules in the given {@code
* Configuration} to the Java virtual machine. Each module is defined to
* its own {@link ClassLoader} created by this method. The {@link
* ClassLoader#getParent() parent} of each class loader is the given parent
* class loader.
*
* <p> The class loaders created by this method implement <em>direct
* delegation</em> when loading classes from modules. If the {@link
* ClassLoader#loadClass(String, boolean) loadClass} method is invoked to
* load a class then it uses the package name of the class to map it to a
* module. The package may be in the module defined to the class loader.
* The package may be exported by another module in this layer to the
* module defined to the class loader. It may be in a package exported by a
* module in a parent layer. The class loader delegates to the class loader
* of the module, throwing {@code ClassNotFoundException} if not found by
* that class loader. When {@code loadClass} is invoked to load a class
* that does not map to a module then it delegates to the parent class
* loader. </p>
*
* <p> The class loaders created by this method locate resources
* ({@link ClassLoader#getResource(String) getResource}, {@link
* ClassLoader#getResources(String) getResources}, and other resource
* methods) in the module defined to the class loader before searching
* the parent class loader. </p>
*
* <p> If there is a security manager then the class loaders created by
* this method will load classes and resources with privileges that are
* restricted by the calling context of this method. </p>
*
* @param cf The configuration for the layer
* @param parentLayers The list of parent layers in search order
* @param parentLoader The parent class loader for each of the class loaders created by
* this method; may be {@code null} for the bootstrap class loader
*
* @return A controller that controls the newly created layer
*
* @throws IllegalArgumentException If the parent(s) of the given configuration do not match the
* configuration of the parent layers, including order
* @throws LayerInstantiationException If the layer cannot be created because the configuration contains
* a module named "{@code java.base}" or a module contains a package
* named "{@code java}" or a package with a name starting with
* "{@code java.}"
* @throws SecurityException If {@code RuntimePermission("createClassLoader")} or
* {@code RuntimePermission("getClassLoader")} is denied by
* the security manager
* @see #findLoader
*/
/*
* 构造新的模块层
*
* cf : 模块图
* parentLayers: 父模块层
* parentLoader: 所有模块类加载器的父级类加载器(不同的模块使用不同的类加载器)
*/
public static Controller defineModulesWithManyLoaders(Configuration cf, List<ModuleLayer> parentLayers, ClassLoader parentLoader) {
List<ModuleLayer> parents = new ArrayList<>(parentLayers);
checkConfiguration(cf, parents);
checkCreateClassLoaderPermission();
checkGetClassLoaderPermission();
// 使用同一个父级类加载器构造模块类加载器池,不同的模块使用各自的模块类加载器
LoaderPool pool = new LoaderPool(cf, parents, parentLoader);
try {
ModuleLayer layer = new ModuleLayer(cf, parents, pool::loaderFor);
return new Controller(layer);
} catch(IllegalArgumentException | IllegalStateException e) {
throw new LayerInstantiationException(e.getMessage());
}
}
/*▲ 定义模块层 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 关联信息 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Returns the <em>empty</em> layer. There are no modules in the empty
* layer. It has no parents.
*
* @return The empty layer
*/
// 返回一个空的模块层
public static ModuleLayer empty() {
return EMPTY_LAYER;
}
/**
* Returns the boot layer. The boot layer contains at least one module,
* {@code java.base}. Its parent is the {@link #empty() empty} layer.
*
* @return The boot layer
*
* @apiNote This method returns {@code null} during startup and before
* the boot layer is fully initialized.
*/
// 获取 boot layer
public static ModuleLayer boot() {
return System.bootLayer;
}
/**
* Returns the configuration for this layer.
*
* @return The configuration for this layer
*/
// 获取模块图
public Configuration configuration() {
return configuration;
}
/**
* Returns the list of this layer's parents unless this is the
* {@linkplain #empty empty layer}, which has no parents and so an
* empty list is returned.
*
* @return The list of this layer's parents
*/
// 获取父模块层
public List<ModuleLayer> parents() {
return parents;
}
/**
* Returns the set of the modules in this layer.
*
* @return A possibly-empty unmodifiable set of the modules in this layer
*/
// 获取当前模块层内所有模块
public Set<Module> modules() {
Set<Module> modules = this.modules;
if(modules == null) {
this.modules = modules = Set.copyOf(nameToModule.values());
}
return modules;
}
/**
* Returns the module with the given name in this layer, or if not in this
* layer, the {@linkplain #parents() parent} layers. Finding a module in
* parent layers is equivalent to invoking {@code findModule} on each
* parent, in search order, until the module is found or all parents have
* been searched. In a <em>tree of layers</em> then this is equivalent to
* a depth-first search.
*
* @param name The name of the module to find
*
* @return The module with the given name or an empty {@code Optional}
* if there isn't a module with this name in this layer or any
* parent layer
*/
// 在当前模块层以及父模块层中查找指定名称的模块
public Optional<Module> findModule(String name) {
Objects.requireNonNull(name);
if(this == EMPTY_LAYER) {
return Optional.empty();
}
// 先在当前模块层查找
Module m = nameToModule.get(name);
if(m != null) {
return Optional.of(m);
}
// 当前模块层未找到的话去父模块层查找
return layers() // 当前模块层与所有父模块层组成的流
.skip(1) // 跳过当前模块层
.map(l -> l.nameToModule.get(name)) // 获取模块名对应的模块
.filter(Objects::nonNull).findAny();
}
/**
* Returns the {@code ClassLoader} for the module with the given name. If
* a module of the given name is not in this layer then the {@link #parents()
* parent} layers are searched in the manner specified by {@link
* #findModule(String) findModule}.
*
* <p> If there is a security manager then its {@code checkPermission}
* method is called with a {@code RuntimePermission("getClassLoader")}
* permission to check that the caller is allowed to get access to the
* class loader. </p>
*
* @param name The name of the module to find
*
* @return The ClassLoader that the module is defined to
*
* @throws IllegalArgumentException if a module of the given name is not
* defined in this layer or any parent of this layer
* @throws SecurityException if denied by the security manager
* @apiNote This method does not return an {@code Optional<ClassLoader>}
* because `null` must be used to represent the bootstrap class loader.
*/
// 查找指定名称的模块对应的ClassLoader
public ClassLoader findLoader(String name) {
Optional<Module> om = findModule(name);
// can't use map(Module::getClassLoader) as class loader can be null
if(om.isPresent()) {
return om.get().getClassLoader();
} else {
throw new IllegalArgumentException("Module " + name + " not known to this layer");
}
}
/*▲ 关联信息 ████████████████████████████████████████████████████████████████████████████████┛ */
/**
* Returns a string describing this module layer.
*
* @return A possibly empty string describing this module layer
*/
@Override
public String toString() {
return modules().stream().map(Module::getName).collect(Collectors.joining(", "));
}
/**
* Returns a stream of the layers that have at least one module defined to
* the given class loader.
*/
// 返回一个流,其中包含了loader参与定义过的所有模块层
static Stream<ModuleLayer> layers(ClassLoader loader) {
List<ModuleLayer> list = CLV.get(loader);
if(list != null) {
return list.stream();
} else {
return Stream.empty();
}
}
/**
* Returns an ordered stream of layers. The first element is this layer,
* the remaining elements are the parent layers in DFS order.
*
* @implNote For now, the assumption is that the number of elements will
* be very low and so this method does not use a specialized spliterator.
*/
// 深度遍历当前模块层以及父模块层,返回包含了遍历到的所有模块的流
Stream<ModuleLayer> layers() {
List<ModuleLayer> allLayers = this.allLayers;
if(allLayers != null) {
return allLayers.stream();
}
allLayers = new ArrayList<>();
Set<ModuleLayer> visited = new HashSet<>();
Deque<ModuleLayer> stack = new ArrayDeque<>();
visited.add(this);
stack.push(this);
while(!stack.isEmpty()) {
ModuleLayer layer = stack.pop();
allLayers.add(layer);
// push in reverse order
for(int i = layer.parents.size() - 1; i >= 0; i--) {
ModuleLayer parent = layer.parents.get(i);
if(!visited.contains(parent)) {
visited.add(parent);
stack.push(parent);
}
}
}
this.allLayers = allLayers = Collections.unmodifiableList(allLayers);
return allLayers.stream();
}
/**
* Returns the ServicesCatalog for this Layer, creating it if not already created.
*/
// 返回当前模块层的服务目录(包含所有模块内的所有提供的服务)
ServicesCatalog getServicesCatalog() {
ServicesCatalog servicesCatalog = this.servicesCatalog;
if(servicesCatalog != null) {
return servicesCatalog;
}
synchronized(this) {
servicesCatalog = this.servicesCatalog;
if(servicesCatalog == null) {
// 创建一个空的服务目录
servicesCatalog = ServicesCatalog.create();
// 遍历当前模块层所有模块,然后对每个模块内的所有服务进行注册
for(Module module : nameToModule.values()) {
// 注册指定模块内的所有服务,即将指定模块内所有服务及其对应的服务提供者缓存到服务目录中
servicesCatalog.register(module);
}
this.servicesCatalog = servicesCatalog;
}
}
return servicesCatalog;
}
/**
* Record that this layer has at least one module defined to the given
* class loader.
*/
// 将当前模块层缓存到指定loader内部的类加载器局部缓存中
void bindToLoader(ClassLoader loader) {
// 从loader的类加载器局部缓存中提取CLV对象映射的值
List<ModuleLayer> list = CLV.get(loader);
// 如果目标值为空
if(list == null) {
list = new CopyOnWriteArrayList<>();
// 向loader的类加载器局部缓存中存入一个CLV对象到list的映射,并返回旧(目标)值,不允许覆盖
List<ModuleLayer> previous = CLV.putIfAbsent(loader, list);
if(previous != null) {
list = previous;
}
}
list.add(this);
}
/**
* Checks that the parent configurations match the configuration of the parent layers.
*/
private static void checkConfiguration(Configuration cf, List<ModuleLayer> parentLayers) {
Objects.requireNonNull(cf);
List<Configuration> parentConfigurations = cf.parents();
if(parentLayers.size() != parentConfigurations.size())
throw new IllegalArgumentException("wrong number of parents");
int index = 0;
for(ModuleLayer parent : parentLayers) {
if(parent.configuration() != parentConfigurations.get(index)) {
throw new IllegalArgumentException("Parent of configuration != configuration of this Layer");
}
index++;
}
}
private static void checkCreateClassLoaderPermission() {
SecurityManager sm = System.getSecurityManager();
if(sm != null)
sm.checkPermission(SecurityConstants.CREATE_CLASSLOADER_PERMISSION);
}
private static void checkGetClassLoaderPermission() {
SecurityManager sm = System.getSecurityManager();
if(sm != null)
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
/**
* Checks a configuration and the module-to-loader mapping to ensure that
* no two modules mapped to the same class loader have the same package.
* It also checks that no two automatic modules have the same package.
*
* @throws LayerInstantiationException
*/
private static void checkForDuplicatePkgs(Configuration cf, Function<String, ClassLoader> clf) {
// HashMap allows null keys
Map<ClassLoader, Set<String>> loaderToPackages = new HashMap<>();
for(ResolvedModule resolvedModule : cf.modules()) {
ModuleDescriptor descriptor = resolvedModule.reference().descriptor();
ClassLoader loader = clf.apply(descriptor.name());
Set<String> loaderPackages = loaderToPackages.computeIfAbsent(loader, k -> new HashSet<>());
for(String pkg : descriptor.packages()) {
boolean added = loaderPackages.add(pkg);
if(!added) {
throw fail("More than one module with package %s mapped" + " to the same class loader", pkg);
}
}
}
}
/**
* Creates a LayerInstantiationException with the a message formatted from
* the given format string and arguments.
*/
private static LayerInstantiationException fail(String fmt, Object... args) {
String msg = String.format(fmt, args);
return new LayerInstantiationException(msg);
}
/**
* Controls a module layer.
* The static methods defined by {@link ModuleLayer} to create module layers
* return a {@code Controller} that can be used to control modules in the layer.
*
* <p> Unless otherwise specified, passing a {@code null} argument to a
* method in this class causes a {@link NullPointerException
* NullPointerException} to be thrown. </p>
*
* @apiNote Care should be taken with {@code Controller} objects, they
* should never be shared with untrusted code.
* @spec JPMS
* @since 9
*/
// 模块层控制器
public static final class Controller {
private final ModuleLayer layer;
Controller(ModuleLayer layer) {
this.layer = layer;
}
/**
* Returns the layer that this object controls.
*
* @return the module layer
*/
public ModuleLayer layer() {
return layer;
}
/**
* Updates module {@code source} in the layer to read module
* {@code target}. This method is a no-op if {@code source} already
* reads {@code target}.
*
* @param source The source module
* @param target The target module to read
*
* @return This controller
*
* @throws IllegalArgumentException If {@code source} is not in the module layer
* @implNote <em>Read edges</em> added by this method are <em>weak</em>
* and do not prevent {@code target} from being GC'ed when {@code source}
* is strongly reachable.
* @see Module#addReads
*/
// 使模块source依赖(requires)模块target,需要通知VM
public Controller addReads(Module source, Module target) {
ensureInLayer(source);
source.implAddReads(target);
return this;
}
/**
* Updates module {@code source} in the layer to export a package to
* module {@code target}. This method is a no-op if {@code source}
* already exports the package to at least {@code target}.
*
* @param source The source module
* @param pn The package name
* @param target The target module
*
* @return This controller
*
* @throws IllegalArgumentException If {@code source} is not in the module layer or the package
* is not in the source module
* @see Module#addExports
*/
// 将模块source的pn包导出(exports)给模块target,需要通知VM
public Controller addExports(Module source, String pn, Module target) {
ensureInLayer(source);
source.implAddExports(pn, target);
return this;
}
/**
* Updates module {@code source} in the layer to open a package to
* module {@code target}. This method is a no-op if {@code source}
* already opens the package to at least {@code target}.
*
* @param source The source module
* @param pn The package name
* @param target The target module
*
* @return This controller
*
* @throws IllegalArgumentException If {@code source} is not in the module layer or the package
* is not in the source module
* @see Module#addOpens
*/
// 将模块source的pn包(开放)opens给模块target,需要通知VM
public Controller addOpens(Module source, String pn, Module target) {
ensureInLayer(source);
source.implAddOpens(pn, target);
return this;
}
// 确保模块source在当前模块中
private void ensureInLayer(Module source) {
if(source.getLayer() != layer) {
throw new IllegalArgumentException(source + " not in layer");
}
}