java类加载器

1,什么是类加载器?

        加载类的工具.

 

2,类加载器有什么作用?

        当程序需要的某个类,那么需要通过类加载器把类的二进制加载到内存中.

类加载器也是Java类

 

3,类加载器之间的父子关系和管辖范围.

java类加载器_第1张图片

  ClassLoader classLoader = ClassLoadTest.class.getClassLoader();
  while(classLoader != null){
   System.out.println(classLoader.getClass().getName());
   classLoader=classLoader.getParent();
  }
  System.out.println(classLoader);
 结果:
sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$ExtClassLoader
null

4、类加载器的委托机制

 1>当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?

                    ①首先当前线程的类加载器去加载线程中的第一个类.

                    ②如果类A中引用了类B,Java虚拟机将使用加载类A的类加载器加载类B

                    ③还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类.

         2>每个类加载器加载类时,又先委托给其上级类加载器.

                    ①当所有祖宗类加载器没有加载到类

,回到发起者类加载器,如果还加载不了,则抛出ClassNotFoundException异常,它不会 去找发起者类加载器的儿子,因为没有getChild()方法,即使有,有那么多的儿子交给那一个呢?所以干错就不叫给儿子处理了.               

        委托机制有什么好处?集中管理,如果我们写了几个类加载器,都去加载某个类,那么内存中就有多份这个类的字节码

        能不能自己写一个类叫java.lang.System?

为了不让我们写System类,类加载采用委托机制,这样可以保证爸爸优先,也就是使用的永远是爸爸的(系统的)

System类,而不是我们写的System类.

 

5,编写自己的类加载器

public static void main(String[] args) throws Exception {

        String srcPath = args[0];

        String destDir = args[1];

        FileInputStream fis = new FileInputStream(srcPath);

        String destFileName = srcPath.substring(srcPath.lastIndexOf('\\')+1);

        String destPath = destDir + "\\" + destFileName;

        FileOutputStream fos = new FileOutputStream(destPath);

        cypher(fis,fos);

        fis.close();

        fos.close();

    }

 

    /**

     * 加密方法,同时也是解密方法

     * @param ips

     * @param ops

     * @throws Exception

     */

    private static void cypher(InputStream ips ,OutputStream ops) throws Exception{

        int b = -1;

        while((b=ips.read())!=-1){

            ops.write(b ^ 0xff);//如果是1就变成0,如果是0就变成1

        }

    }

然后在新建一个类,通过上面的方法将新建的类的字节码进行加密:

public class ClassLoaderAttachment extends Date { //为什么要继承Date待会再说?

    public String toString(){

        return "hello,itcast";

    } 

}

并在工程里新建一个文件夹,用来保存加密后的class文件.


java类加载器_第2张图片

那么这就需要使用我们自己的类加载器来进行解密了.

public class MyClassLoader extends ClassLoader{

 

    public static void main(String[] args) throws Exception {

        String srcPath = args[0];

        String destDir = args[1];

        FileInputStream fis = new FileInputStream(srcPath);

        String destFileName = srcPath.substring(srcPath.lastIndexOf('\\')+1);

        String destPath = destDir + "\\" + destFileName;

        FileOutputStream fos = new FileOutputStream(destPath);

        cypher(fis,fos);

        fis.close();

        fos.close();

    }

 

    /**

     * 加密方法,同时也是解密方法

     * @param ips

     * @param ops

     * @throws Exception

     */

    private static void cypher(InputStream ips ,OutputStream ops) throws Exception{

        int b = -1;

        while((b=ips.read())!=-1){

            ops.write(b ^ 0xff);//如果是1就变成0,如果是0就变成1

        }

    }

 

    private String classDir;

 

    @Override

    protected Class<?> findClass(String name) throws ClassNotFoundException {

        String classFileName = classDir + "\\" + name.substring(name.lastIndexOf('.')+1) + ".class";

        try {

            FileInputStream fis = new FileInputStream(classFileName);

            ByteArrayOutputStream bos = new ByteArrayOutputStream();

            cypher(fis,bos);

            fis.close();

            System.out.println("aaa");

            byte[] bytes = bos.toByteArray();

            return defineClass(bytes, 0, bytes.length);

        } catch (Exception e) {

            e.printStackTrace();

        }

        return null;

    }

 

    public MyClassLoader(){

    }

 

    public MyClassLoader(String classDir){

        this.classDir = classDir;

    }

}

测试运行代码:

 

        Class clazz = new MyClassLoader("myClass").loadClass("ClassLoaderAttachment");

        //此处不能在使用ClassLoaderAttachment因为一旦用了之后,

        //系统的类加载器就会去加载,导致失败,所以该类就继承了Date类了.

        Date date = (Date)clazz.newInstance();

        System.out.println(date);

运行结果:




6,一个类加载器的高级问题:

        我们知道tomcat服务器,是一个大大的java程序,那么它就必须在JVM上运行.

这个大大的java程序内部也写了很多类加载器,它用这些类加载器去加载一些特定的类.注入servlet类.

下面我们新建一个javaweb工程,新建一个servlet程序.

    public void doGet(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        response.setContentType("text/html");

        PrintWriter out = response.getWriter();

        ClassLoader classload = this.getClass().getClassLoader();

        while (classload != null) {

            out.println(classload.getClass().getName()+"<br>");

            classload = classload.getParent();

        }

        out.println();

        out.close();

    }

然后配置服务器,部署应用程序,启动tomcat服务器.在页面访问我们这个servlet,在页面打印的

结果如下图所示:

 


这是从小到大排序的.

现在呢?我想把该servlet打成jar包,放在ExtClassLoad类加载器加载的路径.

通过Eclipse即可完成


java类加载器_第3张图片



转载请注明出处: http://blog.csdn.net/johnny901114/article/details/7738958

 

 

你可能感兴趣的:(java类加载器)