java自定义classLoader

一般这种课题,首先以就要阅读一下官方提供的帮忙文档

实在是太多了,这里就不全部列出来了。主要罗列了几个概念,以及一些比较重要的语句。

抽象类,双亲委托,亲ClassLoader等。

通过官方提供的样例,我们基本就可以写一个简单的ClassLoader。

java.lang.ClassLoader

A class loader is an object that is responsible for loading classes.The class ClassLoader is an abstract class.

A typical strategy is to transform the name into a file name and then read a "class file" of that name from a file system.

The ClassLoader class uses a delegation model to search for classes and resources.

Each instance of ClassLoader has an associated parent class loader.  When requested to find a class or  resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself.

A sample implementation is:

 * <blockquote><pre>
 *     class NetworkClassLoader extends ClassLoader {
 *         String host;
 *         int port;
 *
 *         public Class findClass(String name) {
 *             byte[] b = loadClassData(name);
 *             return defineClass(name, b, 0, b.length);
 *         }
 *
 *         private byte[] loadClassData(String name) {
 *             // load the class data from the connection
 *             &nbsp;.&nbsp;.&nbsp;.
 *         }
 *     }
 * </pre></blockquote>

package com.dangxk.tools.test;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author dangxk
 */
public class MyClassloader extends ClassLoader {

    private final String fileSuffix = ".class";
    private String classLocation;

    public MyClassloader(String classLocation) {
        super();
        this.classLocation = classLocation;
    }

    public MyClassloader(ClassLoader parentClassLoader, String classLocation) {
        super(parentClassLoader);
        this.classLocation = classLocation;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] classData = loadClassData(name);
        return defineClass(name, classData, 0, classData.length);
    }

    private byte[] loadClassData(String name) {
        InputStream is = null;
        ByteArrayOutputStream baos = null;
        byte[] data = null;
        try {
            is = new FileInputStream(new File(classLocation + name.replace(".", "\\") + fileSuffix));
            baos = new ByteArrayOutputStream();
            int r = 0;
            while (-1 != (r = is.read())) {
                baos.write(r);
            }
            is.close();
            baos.close();
            data = baos.toByteArray();
        } catch (Exception ex) {
            Logger.getLogger(MyClassloader.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                is.close();
                baos.close();
            } catch (IOException exx) {
                Logger.getLogger(MyClassloader.class.getName()).log(Level.SEVERE, null, exx);
            }
        }
        return data;
    }

    @Override
    public String toString() {
        return "This is MyClassLoader:" + this.getClass().getSimpleName();
    }

    public static void main(String[] args) throws Exception {
        MyClassloader myCl = new MyClassloader(ClassLoader.getSystemClassLoader(), "D:\\NetBeansProjects\\tools\\target\\classes\\");
        testClassLoader(myCl);
    }

    private static void testClassLoader(MyClassloader cl) throws Exception {
        Class<?> clazz = cl.findClass("com.dangxk.tools.test.EditDistance");
        System.out.println(clazz.getClassLoader().toString());

        Object newObj = clazz.newInstance();
        System.out.println(newObj.toString());
    }
}

输出:

This is MyClassLoader:MyClassloader
com.dangxk.tools.test.EditDistance@7852e922

实现基类(ClassLoader)的 findClass,通过文件系统读入外部的Class文件,转换成byteArray,生成对应的类。

流程就是这样。

接下来我们简单看一下在实现代码过程中主要用到的几个方法的官方定义。 

    /**
     * Finds the class with the specified <a href="#name">binary name</a>.
     * This method should be overridden by class loader implementations that
     * follow the delegation model for loading classes, and will be invoked by
     * the {@link #loadClass <tt>loadClass</tt>} method after checking the
     * parent class loader for the requested class.  The default implementation
     * throws a <tt>ClassNotFoundException</tt>.
     *
     * @param  name
     *         The <a href="#name">binary name</a> of the class
     *
     * @return  The resulting <tt>Class</tt> object
     *
     * @throws  ClassNotFoundException
     *          If the class could not be found
     *
     * @since  1.2
     */
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        throw new ClassNotFoundException(name);
    }

这里的 binary name就是上面例子中的,com.dangxk.tools.test.EditDistance

binary name官方详解

后面调用 return defineClass(name, classData, 0, classData.length);

就可以把从class文件读入的byteArray转化成对应的Class了。

※ 通过上面这些步骤我们就完成了用 java.lang.ClassLoader 帮助我们实现自定义类加载器的功能。

 

接下来是一些方便自己理解的东西,大家如果没有兴趣可以无视,哈哈。

注意此时我们只是创建了类,并没有加载这个类。

可以通过给 com.dangxk.tools.test.EditDistance 追加静态代码块儿去确认这个观点。

    /**
     * Converts an array of bytes into an instance of class <tt>Class</tt>.
     * Before the <tt>Class</tt> can be used it must be resolved.
     *
     * <p> This method assigns a default {@link java.security.ProtectionDomain
     * <tt>ProtectionDomain</tt>} to the newly defined class.  The
     * <tt>ProtectionDomain</tt> is effectively granted the same set of
     * permissions returned when {@link
     * java.security.Policy#getPermissions(java.security.CodeSource)
     * <tt>Policy.getPolicy().getPermissions(new CodeSource(null, null))</tt>}
     * is invoked.  The default domain is created on the first invocation of
     * {@link #defineClass(String, byte[], int, int) <tt>defineClass</tt>},
     * and re-used on subsequent invocations.
     *
     * <p> To assign a specific <tt>ProtectionDomain</tt> to the class, use
     * the {@link #defineClass(String, byte[], int, int,
     * java.security.ProtectionDomain) <tt>defineClass</tt>} method that takes a
     * <tt>ProtectionDomain</tt> as one of its arguments.  </p>
     *
     * @param  name
     *         The expected <a href="#name">binary name</a> of the class, or
     *         <tt>null</tt> if not known
     *
     * @param  b
     *         The bytes that make up the class data.  The bytes in positions
     *         <tt>off</tt> through <tt>off+len-1</tt> should have the format
     *         of a valid class file as defined by
     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
     *
     * @param  off
     *         The start offset in <tt>b</tt> of the class data
     *
     * @param  len
     *         The length of the class data
     *
     * @return  The <tt>Class</tt> object that was created from the specified
     *          class data.
     *
     * @throws  ClassFormatError
     *          If the data did not contain a valid class
     *
     * @throws  IndexOutOfBoundsException
     *          If either <tt>off</tt> or <tt>len</tt> is negative, or if
     *          <tt>off+len</tt> is greater than <tt>b.length</tt>.
     *
     * @throws  SecurityException
     *          If an attempt is made to add this class to a package that
     *          contains classes that were signed by a different set of
     *          certificates than this class (which is unsigned), or if
     *          <tt>name</tt> begins with "<tt>java.</tt>".
     *
     * @see  #loadClass(String, boolean)
     * @see  #resolveClass(Class)
     * @see  java.security.CodeSource
     * @see  java.security.SecureClassLoader
     *
     * @since  1.1
     */
    protected final Class<?> defineClass(String name, byte[] b, int off, int len)
        throws ClassFormatError
    {
        return defineClass(name, b, off, len, null);
    }
 

哈哈,又是一大堆,defineClass继续王后追的话,最终调用的就是native方法。就接触到了C++的东西了。

    private native Class<?> defineClass0(String name, byte[] b, int off, int len, ProtectionDomain pd);

    private native Class<?> defineClass1(String name, byte[] b, int off, int len, ProtectionDomain pd, String source);

    private native Class<?> defineClass2(String name, java.nio.ByteBuffer b, int off, int len, ProtectionDomain pd, String source);

追到这儿,大家应该就明白了。我们差不多到头了。剩下的就只能参考各种文档,加深一下理解。追代码的方式已经不能继续进行了。

结语:

总之,从自定义类加载器入手,进一步理解java类加载相关的周边知识。其实这些东西可能在我们平时开发的时候基本上不会用到,但是理解了这些东西就能更好的接近基地实现。挖深一步,就更自信一点儿。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值