/**
* 检查类签名
* 限制同一个包的类的签名是一样的,防止其他包替换自己包的某一个类
* 这就会造成这样一种问题:不同版本的同一个包,会报该方法内的异常,一般检查
* 下是否有版本冲突即可
*/
private void checkCerts(String name, CodeSource cs) {
int i = name.lastIndexOf('.');
String pname = (i == -1) ? "" : name.substring(0, i);
Certificate[] certs = null;
if (cs != null) {
certs = cs.getCertificates();
}
Certificate[] pcerts = null;
if (parallelLockMap == null) {
synchronized (this) {
pcerts = package2certs.get(pname);
if (pcerts == null) {
package2certs.put(pname, (certs == null? nocerts:certs));
}
}
} else {
pcerts = ((ConcurrentHashMap<String, Certificate[]>)package2certs).
putIfAbsent(pname, (certs == null? nocerts:certs));
}
if (pcerts != null && !compareCerts(pcerts, certs)) {
throw new SecurityException("class \""+ name +
"\"'s signer information does not match signer information of other classes in the same package");
}
}
/**
* 检查两个签名数组是否相同,看代码可知,只要求数量一致,对象一致,但不
* 要求顺序
*/
private boolean compareCerts(Certificate[] pcerts,
Certificate[] certs)
{
// certs can be null, indicating no certs.
if ((certs == null) || (certs.length == 0)) {
return pcerts.length == 0;
}
// the length must be the same at this point
if (certs.length != pcerts.length)
return false;
// go through and make sure all the certs in one array
// are in the other and vice-versa.
boolean match;
for (int i = 0; i < certs.length; i++) {
match = false;
for (int j = 0; j < pcerts.length; j++) {
if (certs[i].equals(pcerts[j])) {
match = true;
break;
}
}
if (!match) return false;
}
// now do the same for pcerts
for (int i = 0; i < pcerts.length; i++) {
match = false;
for (int j = 0; j < certs.length; j++) {
if (pcerts[i].equals(certs[j])) {
match = true;
break;
}
}
if (!match) return false;
}
return true;
}
/**
* 解析类,链接指定的Java类,这里的链接即Java类装载的步骤2,详情可见
* https://blog.csdn.net/a327369238/article/details/52068692
*/
protected final void resolveClass(Class<?> c) {
resolveClass0(c);
}
private native void resolveClass0(Class c);
/**
* 从本地文件系统中加载指定类(字节码)
* 加载类的缺省方法
*/
protected final Class<?> findSystemClass(String name)
throws ClassNotFoundException
{
ClassLoader system = getSystemClassLoader();
if (system == null) {
if (!checkName(name))
throw new ClassNotFoundException(name);
Class cls = findBootstrapClass(name);
if (cls == null) {
throw new ClassNotFoundException(name);
}
return cls;
}
return system.loadClass(name);
}
/**
* 启动类加载器类
*/
private Class findBootstrapClassOrNull(String name)
{
if (!checkName(name)) return null;
return findBootstrapClass(name);
}
private native Class findBootstrapClass(String name);
/**
* 获取缓存的,已加载的指定类
* 若指定的类,未加载,则返回null(即查看是否有加载该类)
*/
protected final Class<?> findLoadedClass(String name) {
if (!checkName(name))
return null;
return findLoadedClass0(name);
}
private native final Class findLoadedClass0(String name);
/**
* 设置类的签名
*/
protected final void setSigners(Class<?> c, Object[] signers) {
c.setSigners(signers);
}
// -- Resource --
/**
* 根据给定名称获取对应的资源数据,资源可以是图片、视频、音频、文本等
* 加载顺序类似双亲委派,优先由父类尝试加载
*/
public URL getResource(String name) {
URL url;
if (parent != null) {
url = parent.getResource(name);
} else {
url = getBootstrapResource(name);
}
if (url == null) {
url = findResource(name);
}
return url;
}
/**
* 同上,但略有差异,上方只查一个(只要一个loader加载即为成功),而本
* 方法返回两个:父类加载器加载所得,以及本身加载所得
*/
public Enumeration<URL> getResources(String name) throws IOException {
Enumeration[] tmp = new Enumeration[2];
if (parent != null) {
tmp[0] = parent.getResources(name);
} else {
tmp[0] = getBootstrapResources(name);
}
tmp[1] = findResources(name);
return new CompoundEnumeration<>(tmp);
}
/**
* 各个如何加载资源,各个加载器自行实现,默认返回null
*/
protected URL findResource(String name) {
return null;
}
/**
* 各个如何加载资源,各个加载器自行实现,默认返回空
*/
protected Enumeration<URL> findResources(String name) throws IOException {
return java.util.Collections.emptyEnumeration();
}
/**
* 注册为并行加载,默认的三种加载器均已实现
* 该方法始于1.7,在1.7之前,同一个类只能串行加载(synchronized锁)
* 一旦声明为并行加载,不可回退
* 是否具有并行加载,需要:
* 1.该classloader未被创建(未被加载实例化)
* 2.该类及其所有父类均具有并行加载能力方可
* 注册了ClassLoader为并行加载,则loadClass的时候,锁的粒度是
* className,否则锁的粒度是ClassLoader实例本身this
*/
@CallerSensitive
protected static boolean registerAsParallelCapable() {
Class<? extends ClassLoader> callerClass =
Reflection.getCallerClass().asSubclass(ClassLoader.class);
return ParallelLoaders.register(callerClass);
}
/**
* 获取系统资源(通过SystemClassLoader获取资源)
*/
public static URL getSystemResource(String name) {
ClassLoader system = getSystemClassLoader();
if (system == null) {
return getBootstrapResource(name);
}
return system.getResource(name);
}
/**
* 同上
*/
public static Enumeration<URL> getSystemResources(String name)
throws IOException
{
ClassLoader system = getSystemClassLoader();
if (system == null) {
return getBootstrapResources(name);
}
return system.getResources(name);
}
/**
* 获取启动类资源,以启动类为根路径
*/
private static URL getBootstrapResource(String name) {
URLClassPath ucp = getBootstrapClassPath();
Resource res = ucp.getResource(name);
return res != null ? res.getURL() : null;
}
/**
* 同上
*/
private static Enumeration<URL> getBootstrapResources(String name)
throws IOException
{
final Enumeration<Resource> e =
getBootstrapClassPath().getResources(name);
return new Enumeration<URL> () {
public URL nextElement() {
return e.nextElement().getURL();
}
public boolean hasMoreElements() {
return e.hasMoreElements();
}
};
}
// 启动类路径
static URLClassPath getBootstrapClassPath() {
return sun.misc.Launcher.getBootstrapClassPath();
}
/**
* 获取资源,以流的方式返回
*/
public InputStream getResourceAsStream(String name) {
URL url = getResource(name);
try {
return url != null ? url.openStream() : null;
} catch (IOException e) {
return null;
}
}
/**
* 获取系统资源,以流的方式返回
*/
public static InputStream getSystemResourceAsStream(String name) {
URL url = getSystemResource(name);
try {
return url != null ? url.openStream() : null;
} catch (IOException e) {
return null;
}
}
总结:
这段主要关注于资源的获取,这里的资源可以是文件、图片、视频等等资源,资源的路径也可以是本地的、远程的、绝对路径、相对路径,各种获取资源的方式,以及返回资源数据的数据格式等。