关于java中ClassLoader的一些看法

    由于最近的一个项目需要使用到java的反射机制,所以最近也是好好看了一下java的ClassLoader,目前也只完成了一个可以读取某一个文件夹中的所有类的Loader.

    我们都知道,自定义的ClassLoader都是需要重写几个方法的,比如:findResource.findClass.但是很少有文章详细的所以下ClassLoader的调用顺序.先说一下代码吧:

    

public class MyClassLoader extends ClassLoader {
	private String BaseDir = new String();
	Logger logger = Logger.getLogger("MyClassLoader");
	/**
     * @param name 形如"java.lang.String"的字符串
     * {@inheritDoc}
     */
    @Override
    protected Class<?> findClass(String name)
            throws ClassNotFoundException {
    	logger.log(Level.INFO, "findClass");
        byte[] bytes = loadClassBytes(name);
        Class theClass = defineClass(name, bytes, 0, bytes.length);
        if (theClass == null)
            throw new ClassFormatError();
        return theClass;
    }
    private byte[] loadClassBytes(String className) throws
            ClassNotFoundException {
    	logger.log(Level.INFO, "loadClassBytes");
        try {
            String classFile = getClassFile(className);
            FileInputStream fis = new FileInputStream(classFile);
            FileChannel fileC = fis.getChannel();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            WritableByteChannel outC = Channels.newChannel(baos);
            ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
            while (true) {
                int i = fileC.read(buffer);
                if (i == 0 || i == -1) {
                    break;
                }
                buffer.flip();
                outC.write(buffer);
                buffer.clear();
            }
            fis.close();
            return baos.toByteArray();
        } catch (IOException fnfe) {
            throw new ClassNotFoundException(className);
        }
    }
    private String getClassFile(String name) {
    	logger.log(Level.INFO, "getClassFile");
        StringBuffer sb = new StringBuffer(getBaseDir());
        name = name.replace('.', File.separatorChar) + ".class";
        sb.append(File.separator + name);
        return sb.toString();
    }
    private String getBaseDir() {
        return BaseDir;
    }
    public void setBaseDir(String basedir){
    	BaseDir = basedir;
    }
    // 新增的一个findResource方法
    @Override
    protected URL findResource(String name) {
    	logger.log(Level.INFO, "findResource");
        try {
            URL url = super.findResource(name);
            if (url != null)
                return url;
            url = new URL("file:///" + converName(name));
            // 简化处理,所有资源从文件系统中获取
            return url;
        } catch (MalformedURLException mue) {
            throw new RuntimeException(mue);
        }
    }
    private String converName(String name) {
    	logger.log(Level.INFO, "converName");
        StringBuffer sb = new StringBuffer(getBaseDir());
        name = name.replace('.', File.separatorChar);
        sb.append(File.separator + name);
        return sb.toString();
    }
}

    这就是全部的代码,然后我们在main函数里调用load函数,会出现以下内容:

    点击查看原图

    我们可以看到,Loader函数的执行顺序是: findClass–>loadClassBytes–>getClassFile.所以,如果我们需要自定义我们自己的ClassLoader只需要按着顺序进行修改就行了.

    至于main函数吧,就是这样的:

MyClassLoader classLoader = new MyClassLoader();
classLoader.setBaseDir("Classes/");
Class<?> class1 = classLoader.loadClass("test");
for (Method method : class1.getMethods()) {
	System.out.println(method.getName());
}
Method method = class1.getMethod("sayHello", null);
method.invoke(class1.newInstance(), null);

    我把所有的class文件放在Classes文件夹之下,看上去是这样的:

    点击查看原图

    这是test.class的代码:

public class test{
	public static void main(String[] args){
		System.out.println("Hello World!");
	}
	public void sayHello(){
		System.out.println("Hello World!");
	}
}

    

    于是这样,我们得到了好的结果:

    点击查看原图

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.