,询问安全管理器是否允许程序创建当前处理的类。如果不行,则抛出一个安全异常。这一步可选,如果实现,则需要在findClass()的开始处完成。这一步不是在操作开始时完成,而是在询问父类装载器之后进行。这一步对应为defineClassInPackage权限。
5,向一个字节数组中读入类文件。读取文件以及创建字节数组的方式因类加载器不同而不同。在findClass()中完成。
6,为该类创建合适的保护域。保护域可以来自默认安全模型(即从策略文件中得到),也可以由类加载器扩展。还有一种方法是可以创建一个代码源对象,并采用其保护域定义。这一步也在findClass()中完成。
7,在findClass()方法中,通过调用defineClass()方法,可以由字节码构造一个Class对象。如果使用的是第6步中的代码源,则需要调用getPermissions()方法查找与代码源相关的权限。defineClass()方法还保证了字节码必须通过字节码校验器的检查。
8,最后还需要解析该类。即它所直接引用的类也应由当前类加载器找到。只有直接引用的才算,作为实例变量、方法参数或局部变量来使用的类不算。这一步在loadClass()中完成。对应上面代码中的resovleClass()。
以URLClassLoader举例。
1,对应的代码如下:
public final ClassloadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First check if we have permission to access the package. This
// should go away once we've added support for exported packages.
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
int i = name.lastIndexOf('.');
if (i != -1) {
sm.checkPackageAccess(name.substring(0, i));
}
}
return super.loadClass(name, resolve);
}
URLClassLoader的newInstance()方法会构造一个内部的工厂加载器类。这个类的loadClass()方法做了checkPackageAccess的事情。
2,3 两步与超级父类ClassLoader相同。就是上面ClassLoader的loadClass()做的事情。
4,5,6,7 四个步骤涉及到findClass()方法,URLClassLoader覆盖了findClass()方法,但是最新版的jdk,其实将这几个步骤做的事情都在defineClass()里做掉了。里面的逻辑实现如下:
protected ClassfindClass(final String name)
throws ClassNotFoundException
{
final Classresult;
try {
result = AccessController.doPrivileged(
new PrivilegedExceptionAction