学习Tomcat动态加载JSP的Class类

系统 1673 0

今天在修改项目一个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,并执行

学习Tomcat动态加载JSP的Class类

学习Tomcat动态加载JSP的Class类


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论