关于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 *