• 学习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,并执行


  • 相关阅读:
    C++ 类的本质 札记
    eclipse makefile
    boost 简介
    telecom 产品分析js
    javascript 得到页面参数
    ajax 接口统一模式
    备份
    jquery 元素插入详解
    使用WebClient制作一下简单的采集器
    数据库锁机制
  • 原文地址:https://www.cnblogs.com/TomSnail/p/4372564.html
Copyright © 2020-2023  润新知