java类加载器总结
2015-09-21 11:21
344 查看
类加载的原理:就是通过一个类包的完整名称来加载某个类。
至于类的加载顺序,网上很多。
类加载加载类的方式,我总结了大概有以下几种,欢迎板砖。
直接new
一个ClassLoader
,实现内部匿名类
要实现加载类,可以重写loadClass方法,然后调用ClassLoader的defineClass方法;比如:
ClassLoader myClassLoader =
new ClassLoader() {
@Override
public Class<?> loadClass(String name)
throws ClassNotFoundException{
try {
String fileName = name.substring(name.lastIndexOf(".")+1)+".class";
InputStream is = LoadClass.class.getResourceAsStream(fileName);
if (is==null) {
return
super.loadClass(name);
}
byte[] b =
new byte[is.available()];
is.read(b);
return defineClass(name, b, 0, b.length);
} catch (Exception e) {
throw
new ClassNotFoundException(name);
}
}
};
如果要想加载package下面的某个类,需要这样写
Object obj = myClassLoader.loadClass(PackageName+类名);
例如:myClassLoader.loadClass("feinno.proxy.entityClass."+”Flags”);
此时类加载器的结构为
myClassLoaderà sun.misc.Launcher$AppClassLoader@1bcfbeàsun.misc.Launcher$ExtClassLoader@3f3fbd
解释为
本类的加载器,它的父加载器为AppClassLoader,AppClassLoader的父加载器为ExtClassLoader。
这个加载器的加载顺序是myClassLoader要加载某个类,若找不到该类,就会请求父加载器加载,若此时父加载器也找不到,则会请求父加载器的父加载器加载,如此下去仍找不到会抛出异常ClassNotFoundException。
这种类型的加载器加载的类定的,就是该类所在的package下的所有类,超出这个package就加载不到。(我试验的结果是这样的)
通过URL来加载,可以加载指定的URL下的类
String filePath =”xxxxxxxxxx”;
URL[] urls =
new URL[] {new
URL(filePath)};(这个里面可以放多个URL)
URLClassLoader ul =
new URLClassLoader(urls);
Class c = ul.loadClass("feinno.proxy.entityClass"+"."+name);
这样就可以通过指定的URL,然后通过查找整个package+name就可以找到自己要加载的类。最后ul要关闭。
继承ClassLoader ,类似方法2,也是通过URL来加载类,但是获取类又采用方法1的形式
例如:
String filePath =
“xxxxxxxxxxxxxxxxxx”;
File file = new File(filePath);
URL url = file.toURL();
URLConnection con = url.openConnection();
InputStream is = con.getInputStream();
if (is==null) {
System.out.println("null");
getSystemClassLoader();
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte buf[] =
new byte[1024];
//读取文件流
for (int i = 0; (i = classIs.read(buf)) != -1; ) {
baos.write(buf, 0, i);
}
classIs.close();
baos.close();
//创建新的类对象
byte[] data = baos.toByteArray();
defineClass(name, data, 0, data.length);
可以获取到类的字节流,但是要第三方类包
asm-all-3.3.1.jar,很简单的两句代码就可以获取到类的字节流,然后打印出该类变量,如下:
ClassReader reader = new ClassReader(new FileInputStream(filePath+"main/java/feinno/proxy/entityClass/"+name+".class"));
ClassNode cn = new ClassNode();
reader.accept(cn, 0);
Field[] fiels=cn.getClass().getDeclaredFields();
System.out.println("@@"+fiels.length);
for(int i=0;i<fiels.length;i++){
System.out.println(fiels[i]);
}
其他方法获取类如Class.forName(“xxx”)等等,可以看jdk
API文档
一般用URLClassLoader时,它的类加载结构为java.net.URLClassLoader@13e846f,父加载器为AppClassLoader,ExtClassLoader,null。Web工程的类加载器的结构为WebappClassLoader,StandardClassLoader,AppClassLoader,ExtClassLoader,null(事实上是启动类加载器,也就是启动时的bootstrap classloader)。而上层类加载器能加载的jar包是一定的,所以一个web工程里如果用到URLClassLoader时,很可能会包类与类转换错误等,此时解决办法就是把URLClassLoader类加载器直接定位到WebappClassLoader,然后再反射到addURL(),再把指定的URL加到URLClassLoader中,方法如下:
private static Method addURL = initAddMethod();
private
static URLClassLoader
classLoader = (URLClassLoader) ResolveJAR.class.getClassLoader();//为了和把类加载器调成同一个
/**
*
初始化addUrl
方法.
*
@return
可访问addUrl方法的Method对象
*/
private static Method initAddMethod() {
try {
Method add = URLClassLoader.class.getDeclaredMethod("addURL",
new Class[] { URL.class });
add.setAccessible(true);
return add;
}
catch (Exception e) {
throw
new RuntimeException(e);
}
}
/**
*
通过filepath加载文件到classpath。
*
@param filePath
文件路径
* @return URL
*
@throws Exception
异常
*/
private
static void addURL(URL url) {
try {
addURL.invoke(classLoader,
new Object[] { url });
}
catch (Exception e) {
}
}
至于类的加载顺序,网上很多。
类加载加载类的方式,我总结了大概有以下几种,欢迎板砖。
直接new
一个ClassLoader
,实现内部匿名类
要实现加载类,可以重写loadClass方法,然后调用ClassLoader的defineClass方法;比如:
ClassLoader myClassLoader =
new ClassLoader() {
@Override
public Class<?> loadClass(String name)
throws ClassNotFoundException{
try {
String fileName = name.substring(name.lastIndexOf(".")+1)+".class";
InputStream is = LoadClass.class.getResourceAsStream(fileName);
if (is==null) {
return
super.loadClass(name);
}
byte[] b =
new byte[is.available()];
is.read(b);
return defineClass(name, b, 0, b.length);
} catch (Exception e) {
throw
new ClassNotFoundException(name);
}
}
};
如果要想加载package下面的某个类,需要这样写
Object obj = myClassLoader.loadClass(PackageName+类名);
例如:myClassLoader.loadClass("feinno.proxy.entityClass."+”Flags”);
此时类加载器的结构为
myClassLoaderà sun.misc.Launcher$AppClassLoader@1bcfbeàsun.misc.Launcher$ExtClassLoader@3f3fbd
解释为
本类的加载器,它的父加载器为AppClassLoader,AppClassLoader的父加载器为ExtClassLoader。
这个加载器的加载顺序是myClassLoader要加载某个类,若找不到该类,就会请求父加载器加载,若此时父加载器也找不到,则会请求父加载器的父加载器加载,如此下去仍找不到会抛出异常ClassNotFoundException。
这种类型的加载器加载的类定的,就是该类所在的package下的所有类,超出这个package就加载不到。(我试验的结果是这样的)
通过URL来加载,可以加载指定的URL下的类
String filePath =”xxxxxxxxxx”;
URL[] urls =
new URL[] {new
URL(filePath)};(这个里面可以放多个URL)
URLClassLoader ul =
new URLClassLoader(urls);
Class c = ul.loadClass("feinno.proxy.entityClass"+"."+name);
这样就可以通过指定的URL,然后通过查找整个package+name就可以找到自己要加载的类。最后ul要关闭。
继承ClassLoader ,类似方法2,也是通过URL来加载类,但是获取类又采用方法1的形式
例如:
String filePath =
“xxxxxxxxxxxxxxxxxx”;
File file = new File(filePath);
URL url = file.toURL();
URLConnection con = url.openConnection();
InputStream is = con.getInputStream();
if (is==null) {
System.out.println("null");
getSystemClassLoader();
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte buf[] =
new byte[1024];
//读取文件流
for (int i = 0; (i = classIs.read(buf)) != -1; ) {
baos.write(buf, 0, i);
}
classIs.close();
baos.close();
//创建新的类对象
byte[] data = baos.toByteArray();
defineClass(name, data, 0, data.length);
可以获取到类的字节流,但是要第三方类包
asm-all-3.3.1.jar,很简单的两句代码就可以获取到类的字节流,然后打印出该类变量,如下:
ClassReader reader = new ClassReader(new FileInputStream(filePath+"main/java/feinno/proxy/entityClass/"+name+".class"));
ClassNode cn = new ClassNode();
reader.accept(cn, 0);
Field[] fiels=cn.getClass().getDeclaredFields();
System.out.println("@@"+fiels.length);
for(int i=0;i<fiels.length;i++){
System.out.println(fiels[i]);
}
其他方法获取类如Class.forName(“xxx”)等等,可以看jdk
API文档
一般用URLClassLoader时,它的类加载结构为java.net.URLClassLoader@13e846f,父加载器为AppClassLoader,ExtClassLoader,null。Web工程的类加载器的结构为WebappClassLoader,StandardClassLoader,AppClassLoader,ExtClassLoader,null(事实上是启动类加载器,也就是启动时的bootstrap classloader)。而上层类加载器能加载的jar包是一定的,所以一个web工程里如果用到URLClassLoader时,很可能会包类与类转换错误等,此时解决办法就是把URLClassLoader类加载器直接定位到WebappClassLoader,然后再反射到addURL(),再把指定的URL加到URLClassLoader中,方法如下:
private static Method addURL = initAddMethod();
private
static URLClassLoader
classLoader = (URLClassLoader) ResolveJAR.class.getClassLoader();//为了和把类加载器调成同一个
/**
*
初始化addUrl
方法.
*
@return
可访问addUrl方法的Method对象
*/
private static Method initAddMethod() {
try {
Method add = URLClassLoader.class.getDeclaredMethod("addURL",
new Class[] { URL.class });
add.setAccessible(true);
return add;
}
catch (Exception e) {
throw
new RuntimeException(e);
}
}
/**
*
通过filepath加载文件到classpath。
*
@param filePath
文件路径
* @return URL
*
@throws Exception
异常
*/
private
static void addURL(URL url) {
try {
addURL.invoke(classLoader,
new Object[] { url });
}
catch (Exception e) {
}
}
相关文章推荐
- java SortedMap 升序、降序操作
- 用Jersey构建RESTful服务2--JAVA对象转成XML输出
- 请谨慎使用Java基本类型的对象类
- Spring MVC hello world annotation example
- Spring mvc 绑定Date日期
- java SE复习笔记32
- 一道经典的Java多线程编程题
- java SE复习笔记31
- 无法debug断点跟踪JDK源代码
- 帮助文档的制作javadoc
- Java注释规范
- OAuth 2.0系列教程(十一) 客户端证书请求和响应
- JAVA语言DES算法
- OAuth 2.0系列教程(九) 契约请求和响应
- OAuth 2.0系列教程(八) 授权码授权
- 【JAVA】---String 类
- Java学习之路:不走弯路,就是捷径
- OAuth 2.0系列教程(七) 请求和响应
- OAuth 2.0系列教程(六) 端点
- OAuth 2.0系列教程(五) 授权