学习Tomcat动态加载JSP的Class类

9/6/2015来源:Java教程人气:2630

学习Tomcat动态加载jsp的Class类

今天在修改项目一个JSP文件时,突然想到Tomat是怎么实现动态实时加载JSP编译后的class类的?

查了半天资料,看了很多文章,终于明白是怎么回事了:ClassLoader,当tomcat发现jsp改变后,将用新的ClassLoader去加载新的类

具体原理我将单独总结一下,这里简单实现了动态加载类

1.定义服务类

public class Servlet {    public void service(){        System.out.PRintln("运行服务方法");    }    }

2.定义服务线程

public class ServiceThread extends Thread{    public void run(){        try {            ClassLoader classLoader = this.getContextClassLoader();            Class clazz = classLoader.loadClass("Servlet");            Method service = clazz.getMethod("service", null);            service.invoke(clazz.newInstance(), null);        } catch (Exception e) {            e.printStackTrace();        }    }}

3.自定义ClassLoader

public class MyClassLoader extends ClassLoader{    @Override    public Class loadClass(String name, boolean resolve) throws ClassNotFoundException{        try {                        // 我们要创建的Class对象            Class clasz = null;            // 必需的步骤1:如果类已经在系统缓冲之中            // 我们不必再次装入它            clasz = findLoadedClass(name);            if (clasz != null)                return clasz;            try {                // 读取经过加密的类文件                if(name.equals("Servlet")){            //加载class文件字节                    byte classData[] = Util.readFile(ProgramPathHelper.getProgramPath()+"/"+name + ".class");                    if (classData != null) {                        // ... 再把它转换成一个类                        clasz = defineClass(name, classData, 0,                                classData.length);                    }                }                            } catch (Exception e) {                e.printStackTrace();            }                        // 必需的步骤2:如果上面没有成功            // 我们尝试用默认的ClassLoader装入它            if (clasz == null)                clasz = findSystemClass(name);            // 必需的步骤3:如有必要,则装入相关的类            if (resolve && clasz != null)                resolveClass(clasz);            // 把类返回给调用者            return clasz;        } catch (Exception ie) {            throw new ClassNotFoundException(ie.toString());        }     }}

4.实现文件监听类

public class CCFileListener implements FileAlterationListener{    public static HashMap<String,ClassLoader> claMap = new HashMap<String, ClassLoader>();        ZJPFileMonitor monitor = null;    @Override    public void onStart(FileAlterationObserver observer) {        //System.out.println("onStart");    }    @Override    public void onDirectoryCreate(File directory) {        System.out.println("onDirectoryCreate:" +  directory.getName());    }    @Override    public void onDirectoryChange(File directory) {        System.out.println("onDirectoryChange:" + directory.getName());    }    @Override    public void onDirectoryDelete(File directory) {        System.out.println("onDirectoryDelete:" + directory.getName());    }    @Override    public void onFileCreate(File file) {        System.out.println("onFileCreate:" + file.getName());        dyncLoadClass(file.getName());    }    @Override    public void onFileChange(File file) {     //文件改变处理函数        System.out.println("onFileChange : " + file.getName());                dyncLoadClass(file.getName());            }        private void dyncLoadClass(String className){        if(className.contains("Servlet")){//            ZJPFileMonitor.thread.setContextClassLoader(new MyClassLoader());            claMap.put(className, new MyClassLoader());        }    }    @Override    public void onFileDelete(File file) {        System.out.println("onFileDelete :" + file.getName());    }    @Override    public void onStop(FileAlterationObserver observer) {        //System.out.println("onStop");    }}
public class CCFileMonitor {            FileAlterationMonitor monitor = null;    public CCFileMonitor(long interval) throws Exception {        monitor = new FileAlterationMonitor(interval);    }    public void monitor(String path, FileAlterationListener listener) {        FileAlterationObserver observer = new FileAlterationObserver(new File(path));        monitor.addObserver(observer);        observer.addListener(listener);    }    public void stop() throws Exception{        monitor.stop();    }    public void start() throws Exception {        monitor.start();    }    public static void main(String[] args) throws Exception {        CCFileMonitor m = new CCFileMonitor(5000);        m.monitor(ProgramPathHelper.getProgramPath(),new CCFileListener());        m.start();                Servlet servlet = new Servlet();        servlet.service();        MyClassLoader defaultCl = new MyClassLoader();        while(true){                        Thread.currentThread().sleep(3000);                            Thread t = new ServiceThread();                //设置新线程的类加载器                ClassLoader classLoader = CCFileListener.claMap.get("Servlet.class");                if(classLoader==null){                    classLoader = defaultCl;                }                                t.setContextClassLoader(classLoader);                t.start();                            }        }}
public static HashMap<String,ClassLoader> claMap = new HashMap<String, ClassLoader>();在监听到文件改变后,依据类名重new一个类加载器,用于加载类。
 ClassLoader classLoader = CCFileListener.claMap.get("Servlet.class");
if(classLoader==null){   classLoader = defaultCl;}
 首先获取类名对应的加载器,如果没有使用默认的加载器
 ClassLoader classLoader = this.getContextClassLoader(); Class clazz = classLoader.loadClass("Servlet"); Method service = clazz.getMethod("service", null); service.invoke(clazz.newInstance(), null);在线程内部使用刚才在外部设置的线程上下文加载器加载新的Servlet,并执行