JAVA CLASS LOADING技术研究---整理后的代码

Posted on 2007-04-18 12:55 久城 阅读(5141) 评论(4)  编辑  收藏 所属分类: JavaTest
以下是整理后的代码部分,欢迎批评指正。

MyClassLoader.java
/*
 * @MyClassLoader.java    07/04/17
 *
 * Copyright Zhao Jiucheng. All rights reserved.
 
*/

package com.neusoft.classloader;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Hashtable;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

/**
 * A class loader is an object that is responsible for loading classes. Given
 * the binary name of a class, a class loader should attempt to locate or
 * generate data that constitutes a definition for the 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.
 * 
 * 
@version 1.0, 07/04/17
 * 
@author Zhao Jiucheng
 * 
 
*/

public class MyClassLoader extends ClassLoader {

    
// a classpath for search
    private static String myClasspath = new String("");

    
// hashtable that memory the loaded classes
    private static Hashtable<String, Class<?>> loadClassHashTable = new Hashtable<String, Class<?>>();

    
// hashtable that memory the time of loading a class
    private static Hashtable<String, Long> loadClassTime = new Hashtable<String, Long>();

    
// the null constructor
    public MyClassLoader() {

    }


    
/**
     * create a classloader and specify a classpath.
     * 
     * 
@param myClasspath
     *            the specified classpath name.
     
*/

    
public MyClassLoader(String myClasspath) {
        
if (!myClasspath.endsWith("\\")) {
            myClasspath 
= myClasspath + "\\";
        }

        MyClassLoader.myClasspath 
= myClasspath;
    }


    
/**
     * set the classpath
     * 
     * 
@param myClasspath
     *            the specified classpath name
     
*/

    
public void SetmyClasspath(String myClasspath) {
        
if (!myClasspath.endsWith("\\")) {
            myClasspath 
= myClasspath + "\\";
        }

        MyClassLoader.myClasspath 
= myClasspath;
    }


    
/**
     * Loads the class with the specified binary name. This method searches for
     * classes in the same manner as the loadClass(String, boolean) method.
     * Invoking this method is equivalent to invoking {loadClass(name,false)}.
     * 
     * 
@param className
     *            The binary name of the class.
     * 
     * 
@return The resulting <tt>Class</tt> object.
     * 
     * 
@throws ClassNotFoundException
     *             If the class was not found.
     
*/

    @SuppressWarnings(
"unchecked")
    
public Class loadClass(String className) throws ClassNotFoundException {
        
return loadClass(className, false);
    }


    
/**
     * Loads the class with the specified binary name. The default
     * implementation of this method searches for classes in the following
     * order:
     * 
     * Invoke {findLoadedClass(String)} to check if the class has already been
     * loaded.
     * 
     * Invoke {findSystemClass(String)} to load the system class.
     * 
     * Invoke the {findClass(String)} method to find the class.
     * 
     * If the class was found using the above steps, and the resolve flag is
     * true, this method will then invoke the {resolveClass(Class)} method on
     * the resulting Class object.
     * 
     * 
@param name
     *            The binary name of the class.
     * 
     * 
@param resolve
     *            If true then resolve the class.
     * 
     * 
@return The resulting Class object.
     * 
     * 
@throws ClassNotFoundException
     *             If the class could not be found.
     
*/

    @SuppressWarnings(
"unchecked")
    
protected Class loadClass(String name, boolean resolve)
            
throws ClassNotFoundException {

        
try {
            Class foundClass 
= findLoadedClass(name);

            
// check if the class has already been loaded.
            if (foundClass != null{
                System.out.println(
"Complete to load the class: " + name);
                
return foundClass;
            }


            
// if the class is systemClass, load the system class by system
            if (name.startsWith("java.")) {
                foundClass 
= findSystemClass(name);
                loadClassHashTable.put(name, foundClass);
                System.out.println(
"System is loading the class: " + name);
                
return foundClass;
            }


            
// invoke the findClass() method to load the class
            try {
                foundClass 
= findClass(name);
            }
 catch (Exception fnfe) {
            }


            
if (resolve && (foundClass != null)) {
                resolveClass(foundClass);
            }

            
return foundClass;
        }
 catch (Exception e) {
            
throw new ClassNotFoundException(e.toString());
        }

    }


    
/**
     * Finds the class with the specified binary name.The default implementation
     * throws a ClassNotFoundException.
     * 
     * 
@param className
     *            The binary name of the class.
     * 
     * 
@return The resulting Class object.
     * 
     * 
@throws ClassNotFoundException
     *             If the class could not be found.
     
*/

    @SuppressWarnings(
"unchecked")
    
public Class findClass(String className) {

        
byte[] classData = null;
        
try {
            classData 
= loadClassData(className);
        }
 catch (IOException e) {
            e.printStackTrace();
        }

        
if( classData == null){
            
return null;
        }


        System.out.println(
"MyClassLoader is loading : " + className + "");
        Class c 
= defineClass(className, classData, 0, classData.length);
        MyClassLoader.loadClassHashTable.put(className, c);
        System.out.println(
"Complete to load the class :" + className);
        
return c;
    }


    
/**
     * Loads the classData with the specified binary name. This method searches
     * for classes in the specified classpath as
     * searchFile(myClasspath,className) method.
     * 
     * 
@param name
     *            The binary name of the class
     * 
     * 
@return The resulting the classData of the class object by byte[]
     * 
     * 
@throws IOException
     *             if have some failed or interrupted I/O operations.
     
*/

    
private byte[] loadClassData(String className) throws IOException {

        String filePath 
= searchFile(myClasspath, className + ".class");

        
if (!(filePath == null || filePath == "")) {

            System.out.println(
"It have found the file : " + className
                    
+ ".  Begin to read the data and load the class。");
            FileInputStream inFile 
= new FileInputStream(filePath);
            
byte[] classData = new byte[inFile.available()];
            inFile.read(classData);
            inFile.close();
            loadClassTime.put(className, 
new File(filePath).lastModified());
            
return classData;
        }
 else {

            filePath 
= searchFile(myClasspath, className + ".java");
            
if (!(filePath == null || filePath == "")) {
                System.out.println(
"It have found the file : " + filePath
                        
+ ".  Begin to translate");
                Runtime.getRuntime().exec(
"javac " + filePath);
                
try {
                    Thread.sleep(
1000);
                }
 catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println(
"Translate it over : " + filePath);
                
return loadClassData(className);
            }
 else {
                System.out
                        .println(
"Haven't found the file, and fail to read the classData!");
                
return null;
            }

        }

    }


    
/**
     * Loads the class with the specified binary name.The default implementation
     * throws a ClassNotFoundException.
     * 
     * 
@param classData
     *            The data of the class.
     * 
@param className
     *            The binary name of the class.
     * 
     * 
@return The resulting Class object.
     * 
     * 
@throws ClassNotFoundException
     *             If the class could not be found.
     
*/

    
public Class loadClass(byte[] classData, String className)
            
throws ClassNotFoundException {

        System.out.println(
"MyClassLoader is loading : " + className + "");
        Class c 
= defineClass(className, classData, 0, classData.length);
        loadClassHashTable.put(className, c);
        System.out.println(
"Complete to load the class :" + className);

        
return c;
    }


    
/**
     * Loads the class with the specified binary name.The default implementation
     * throws a ClassNotFoundException.
     * 
     * 
@param className
     *            The binary name of the class.
     * 
@param jarName
     *            The binary name of the jar that search the class from it.
     * 
     * 
@return The resulting Class object.
     * 
     * 
@throws ClassNotFoundException
     *             If the class could not be found.
     
*/

    
protected Class loadClass(String className, String jarName)
            
throws ClassNotFoundException {

        String jarPath 
= searchFile(myClasspath, jarName + ".jar");
        JarInputStream in 
= null;

        
if (!(jarPath == null || jarPath == "")) {

            
try {
                in 
= new JarInputStream(new FileInputStream(jarPath));
                JarEntry entry;
                
while ((entry = in.getNextJarEntry()) != null{
                    String outFileName 
= entry.getName().substring(
                            entry.getName().lastIndexOf(
"/"+ 1,
                            entry.getName().length());
                    
if (outFileName.equals(className + ".class")) {
                        
if (entry.getSize() == -1{
                            System.err.println(
"error : can't read the file!");
                            
return null;
                        }

                        
byte[] classData = new byte[(int) entry.getSize()];
                        System.out
                                .println(
"It have found the file : "
                                        
+ className
                                        
+ ".  Begin to read the data and load the class。");
                        in.read(classData);
                        
return loadClass(classData, className);
                    }

                }

                System.out.println(
"Haven't found the file " + className
                        
+ " in " + jarName + ".jar.");
            }
 catch (IOException e) {
                e.printStackTrace();
            }
 finally {
                
try {
                    in.close();
                }
 catch (IOException e) {
                    e.printStackTrace();
                }

            }

        }
 else {
            System.out.println(
"Haven't found the jarFile: " + jarName
                    
+ ".jar.");
            
return null;
        }

        
return null;
    }


    
/**
     * Reloads the class with the specified binary name. Needn't have to restart
     * JVM then reload the class.
     * 
     * 
@param className
     *            The binary name of the class need to reload .
     * 
     * 
@return The resulting Class object.
     * 
     * 
@throws ClassNotFoundException
     *             If the class was not found.
     
*/

    
public Class reload(String fileName) {

        String filePath 
= searchFile(myClasspath, fileName + ".class");
        Long a 
= new File(filePath).lastModified();

        
if (!a.equals(loadClassTime.get(fileName))) {
            loadClassHashTable.remove(fileName);
            loadClassTime.remove(fileName);
            
try {
                MyClassLoader mc2 
= new MyClassLoader(myClasspath);
                mc2.loadClass(fileName);
            }
 catch (ClassNotFoundException e) {
                e.printStackTrace();
            }

        }
 else {
            System.out
                    .println(
"The class is the newest version , needn't reloading.");
        }

        
return null;
    }


    
/**
     * search the file with the specified binary name. Needn't have to restart
     * JVM then reload the class.
     * 
     * 
@param classpath
     *            the specified path where we search.
     * 
@param fileName
     *            The binary name of the file that want to search.
     * 
     * 
@return The resulting file path.
     
*/

    
public String searchFile(String classpath, String fileName) {

        String cut 
= fileName.substring(fileName.lastIndexOf('.'), fileName
                .length());
        String path 
= fileName.substring(0, fileName.lastIndexOf('.')).replace(
                
'.''/')
                
+ cut;

        File f 
= new File(classpath + path);
        
if (f.isFile()) {
            
return f.getPath();
        }
 else {
            String objects[] 
= new File(classpath).list();
            
for (int i = 0; i < objects.length; i++{
                
if (new File(classpath + File.separator + objects[i])
                        .isDirectory()) 
{
                    String s 
= searchFile(classpath + objects[i]
                            
+ File.separator, fileName);
                    
if (s == null || s == ""{
                        
continue;
                    }
 else {
                        
return s;
                    }

                }

            }

        }

        
return null;
    }
;

    
public static void main(String[] args) {
        MyClassLoader c1 
= new MyClassLoader(
                
"E:/javawork/teacher's classloader/bin");
        
//MyClassLoader c2 = new MyClassLoader(
        
//        "E:/javawork/teacher's classloader");
        try {
            
while (true{
                c1.loadClass(
"com.neusoft.test.A");
                
//c2.loadClass("com.neusoft.test.B");
                try {
                    Thread.sleep(
300000);
                }
 catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }

        }
 catch (Exception e) {
            e.printStackTrace();
        }

    }

}



MyThread.java
/*
 * @MyThread.java    2007/04/17
 *
 * Copyright Zhao Jiucheng. All rights reserved.
 * 
 
*/

package com.neusoft.classloader;

import java.io.File;


/**
 * Create a Thread to watch the specify directory,if new classes haved
 * appended,load them.
 * 
 * 
@author Zhao Jiucheng
 * 
@version 1.0, 2007/04/17
 
*/


public class MyThread extends Thread {

    
// for get the classpath
    private String filePath;

    
// instantiation a ClassLoader
    private MyClassLoader mcl;

    
/**
     * Constructs a new MyThread for the given path.
     * 
     * 
@param path
     * 
@return null
     
*/

    
public MyThread(String path) {
        
this.filePath = path;
        mcl 
= new MyClassLoader(path);
    }


    
/**
     * Watch pecify directory to search for appended classes time after time.
     * 
     * 
@param filepath
     * 
     * 
@return null
     * 
@exception ClassNotFoundException
     *                if the class could not be found.
     
*/

    
public void search(String filePath) {
        File dir 
= new File(filePath);
        String[] fileList 
= dir.list();
        
for (int i = 0; i < fileList.length; i++{

            
if (new File(filePath + File.separator + fileList[i]).isDirectory()) {

                search(filePath 
+ fileList[i]);
            }
 else if (new File(filePath + File.separator + fileList[i])
                    .isFile()) 
{

                
if (fileList[i].endsWith(".class")) {
                    
try {

                        mcl.loadClass(fileList[i].substring(
0, fileList[i]
                                .length() 
- 6));
                    }
 catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }

                }

            }

        }

    }


    
/**
     * If this thread was constructed using a separate runnable run object, then
     * that runnable object's run method is called;
     * 
     * 
@return null
     * 
@exception InterruptedException
     *                if the thread has been interrupted.
     
*/


    
public void run() {
        
int i = 1;
        
while (true{
            search(filePath);
            System.out.println(
"searching " + i++ + "s");
            
try {
                Thread.sleep(
1000);
            }
 catch (InterruptedException e) {
                e.printStackTrace();
            }

            
if (i == 20{
                System.out.println(
"search over!");
                
break;
            }

        }

    }


    
public static void main(String[] args) {
        MyThread t 
= new MyThread("D:\\soft\\aa");
        t.start();
    }

}


MyURLClassLoader.java
/*
 * @MyURLClassLoader.java    2007/04/17
 *
 * Copyright Zhao Jiucheng. All rights reserved.
 * 
 
*/

package com.neusoft.classloader;

import java.net.*;


/**
 * This class loader is used to load classes and resources from a search path
 * 
 * 
@author Zhao Jiucheng
 * 
@version 1.0, 2007/04/17
 
*/

public class MyURLClassLoader extends URLClassLoader {
    
/**
     * Constructs a new URLClassLoader for the given URLs.
     * 
     * 
@param url
     
*/

    
public MyURLClassLoader(URL[] url) {
        
super(url);
    }


    
/**
     * Finds the class with the specified binary name.
     * 
     * 
@param name
     *            The binary name of the class
     * 
@return The resulting Class object
     * 
     * 
@throws ClassNotFoundException
     *             If the class could not be found
     
*/

    @SuppressWarnings(
"unchecked")
    
public Class findClass(final String name) {
        
try {
            
return super.findClass(name);
        }
 catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        
return null;
    }


    
public static void main(String[] args) {
        URL url 
= null;
        
try {
            url 
= new URL("http://192.168.44.19:8088/Webtest/");
        }
 catch (MalformedURLException e) {
            e.printStackTrace();
        }

        MyURLClassLoader urlClassLoader1 
= new MyURLClassLoader(
                
new URL[] { url });
        Class c1 
= urlClassLoader1.findClass("Tree");
        System.out.println(c1);

    }


}




欢迎来访!^.^!
本BLOG仅用于个人学习交流!
目的在于记录个人成长.
所有文字均属于个人理解.
如有错误,望多多指教!不胜感激!

Feedback

# re: JAVA CLASS LOADING技术研究---整理后的代码  回复  更多评论   

2007-04-18 14:39 by lx
和java原有classloader比好像没有太大improvement ...对于了解class loader原理还是有帮助的

# re: JAVA CLASS LOADING技术研究---整理后的代码  回复  更多评论   

2007-04-19 15:42 by wanglin
除了委托加载,ms还有上下文加载。

后者资料甚少,sun官方也没有提供详细的介绍,而且虽然现在java技术中已经在使用他,但是还是有问题。。。。。。。。

# re: JAVA CLASS LOADING技术研究---整理后的代码  回复  更多评论   

2007-04-19 16:40 by 久城
恩,谢谢,个人感觉问题还挺大。比如Java中暂时还没有提供区分版本的机制,如果使用了比较复杂的类装载器体系结构,在出现了某个包或者类的多个版本时,就有可能出现问题了。

# re: JAVA CLASS LOADING技术研究---整理后的代码  回复  更多评论   

2007-04-19 22:10 by 匿名
版本区分的问题,通过类加载器可以部分的解决(不同的classload下的包是不会冲突的),在深入java虚拟机那本书中,作者提到classload相当于提供了一个名字空间。 如果你说的版本区分是同一个classload下的的确会有问题。 我说的上下文加载比较啰唆。你可以搜索一下

只有注册用户登录后才能发表评论。


网站导航:
 

Copyright © 久城