类加载器及反射机制(三)-ClassLoader

(1)、java.lang.Class 概念:
Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识,记录每个对象所属的类,有哪些属性和方法,选定那些方法
去执行。这些记录都保持在一个是Class类里面。Class类封装一个对象和接口运行时的状态,当装载类时,Class类型的对象自动创建。

 

(2)、类加载器:
BootStrap,ExtClassLoader,AppClassLoader 三个类加载器,每个类负责加载特定位置的类:
类加载器本身就是java 类,BootStrap是用c++写的一个类,它在jVM启动的时候自动加载到
内存,它负责其它类加载器的加载工作。
test 如何测试一个类是由那个类加载器加载的
package cn.com.chenlly.test;

/**
 * @ Class ClassLoaderTest.java @ Description @ Company OpenData @ Author
 * Chenlly E-mail: Chenlly99@Gmail.com @ Version 1.0 @ Date Jul 3, 2010
 */
public class ClassLoaderTest {
 public static void main(String[] args) {
  System.out.println(ClassLoaderTest.class.getClassLoader().getClass()
    .getName());
 }
}
ClassLoaderTest.class 得到这个类对象
ClassLoaderTest.class.getClassLoader() 得到加载这个类对象的类加载器对象

//out put
sun.misc.Launcher$AppClassLoader

测试BootStrap,ExtClassLoader,AppClassLoader三者之间的关系
package cn.com.chenlly.test;

/**
 * @ Class ClassLoaderTest.java @ Description @ Company OpenData @ Author
 * Chenlly E-mail: Chenlly99@Gmail.com @ Version 1.0 @ Date Jul 3, 2010
 */
public class ClassLoaderTest {
 public static void main(String[] args) {
  ClassLoader loader = ClassLoaderTest.class.getClassLoader();
  while(loader!=null){
   System.out.println( loader.getClass().getName());
   loader = loader.getParent();
  }
  System.out.println(loader);
 }
}
//out put
sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$ExtClassLoader
null  //为null 说明这个类加载器是BootStrap
显而易见,这三个类加载器的关系是AppClassLoader->ExtClassLoader->BottStrap
AppClassLoader 只加载ClassPath 指定目录下的jar包
BootStrap 加载 jre/lib/rt.jar 目录下的rt.jar
ExtClassLoader 加载jre/lib/ext/*.jar 目录下的jar

 

(3)、类加载器的委托机制。
当在Ext 目录和 Classpath 下都有一份class 文件时,则首先会在Ext下去加载。这就是类加载器的委托机制。
我们可以写一个自己的类加载器,挂到这个树形结构中。但必须继承java.lang.ClassLoader。
我们自己写个java.lang.System类 会不会加载?
由于类加载器的委托机制,首先委托给AppClassLoader,然后AppClassLoader会委托给ExtClassLoader,ExtClassLoader委托给
BootStrap在 jre/lib/rt.jar 找到了java.lang.System。BootStrap就会把这个类加载进来。而不会去加载jre/lib/ext/
或者classpath 下的那个java.lang.System类。
如果回到发起者类加载器还加载不了,(比如我们写的java类没有配置classpth) 则会抛出ClassNotFoundException 异常。

(4)、编写自己的类加载器
首先对生成的ClassLoaderDate.class加密以后,是无法运行的
只有通过我自己写的一个类加载器解密以后,才可以运行的
步骤(1):对一个.class 文件加密,生产的加密后的文件放在cypherFiles下。
步骤(2):通过自定义的类加载器,在加载cypherFiles目录下的加密以后的.class文件以后哌解密然后放入内存。运行正常。

package cn.com.chenlly.test;
import java.util.Date;

/**
 * @ Class ClassLoaderDate.java
 * @ Description 需要加密的类
 * @ Company OpenData
 * @ Author Chenlly E-mail: Chenlly99@Gmail.com
 * @ Version 1.0
 * @ Date Jul 3, 2010
 */
public class ClassLoaderDate extends Date {
 public String toString(){
  return "Hello Str";
 }
}

package cn.com.chenlly.test;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * @ Class MyClassLoader.java
 * @ Description  自定义的类加载器,继承ClassLoader类
 * @ Company OpenData
 * @ Author Chenlly E-mail: Chenlly99@Gmail.com
 * @ Version 1.0
 * @ Date Jul 3, 2010
 */
public class MyClassLoader extends ClassLoader {
 
 private String fileDir;

 public MyClassLoader(){
  
 }
 
 
 
 public MyClassLoader(String fileDir){
  this.fileDir = fileDir;
 }
 
 //生产加密后的.class 文件到指定目录
 public static void createClassFile(String srcPath,String destDir) throws IOException{
  FileInputStream fis = new FileInputStream(srcPath);
  String destFileName = srcPath.substring(srcPath.lastIndexOf(");
  String destPath = destDir+"
;
  FileOutputStream fos = new FileOutputStream(destPath);
  //加密
  cypher(fis,fos);
  fis.close();
  fos.close();
 }
 
 //加密或解密方法,对二进制数做异或
 public static void cypher(InputStream ips,OutputStream ops) throws IOException{
  int b = -1;
  while((b=ips.read())!=-1){
   ops.write(b^0xff);//对二进制数做异或
  }
 }
 @Override
 protected Class<?> findClass(String name) throws ClassNotFoundException {
  String clazzFileName = fileDir+"
//"+name.substring(name.lastIndexOf(".")+1)+".class";
  try {
   FileInputStream fis = new FileInputStream(clazzFileName);
   ByteArrayOutputStream bos = new ByteArrayOutputStream();
   //解密
   cypher(fis,bos);
   fis.close();
   byte[] bytes = bos.toByteArray();
   return this.defineClass(bytes, 0, bytes.length);
  } catch (Exception e) {
   e.printStackTrace();
  }
  return super.findClass(name);
 }
 
 public static void main(String []args) throws IOException{
  String srcPath = args[0];//.class 文件所在绝对路径,比如D:/workspace/HelloWorld/WebRoot/WEB-INF/classes/cn/com/chenlly/test/ClassLoaderDate.class
  String destPath = args[1]; //加密后的.class 文件所在目录cypherFiles
  createClassFile(srcPath,destPath);
 }
 
}


package cn.com.chenlly.test;

import java.util.Date;

/**
 * @ Class ClassLoaderTest.java
   @ Description  测试客户端
   @ Company OpenData
   @ Author
 * Chenlly E-mail: Chenlly99@Gmail.com
   @ Version 1.0 @ Date Jul 3, 2010
 */
public class ClassLoaderTest {
 public static void main(String[] args) throws ClassNotFoundException,
   InstantiationException, IllegalAccessException {
  // 使用系统类加载器加载文件,抛出异常
  //System.out.println(new ClassLoaderDate().toString());
  // 调用自己的写的类加载器加载文件
  Class clazz = new MyClassLoader("cypherFiles").loadClass("ClassLoaderDate");// 这个加载器被挂在系统加载器树上
  // 注意:如果ClassLoaderDate不继承Date,在这里这样写:ClassLoaderDate d =
  // (ClassLoaderDate) clazz.newInstance();
  // 编译都通不过,因为ClassLoaderDate.class文件是加密以后的,编译器无法识别,所以让它去继承Date
  Date d = (Date) clazz.newInstance();// 通过加载后的字节码创建对象
  System.out.println(d.toString());
 }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值