• 为了实现动态加载而编写的自己的ClassLoader


    Copy备用

    之前客户要求在不重启应用的前提下实现动态增加服务及交易,在网上查了很长时间也没发现类似的技术,最后研究了一下ClassLoader。因为项目是与Spring,一开始我和同事尝试替换源码的class文件,然后调用Spring的refresh()函数刷新上下文,但是发现原来的类没有被新的类替换。于是我看了一下ClassLoader相关的内容,发现默认的系统类加载器加载类后就不会再次加载。然后我想到要定义自己的类加载器,最后可以实现动态替换原来的类了。虽然最后没能应用在项目中,但是初步了解了一下ClassLoader原理让我感觉挺兴奋的,打算以后再做一下深入的研究,先把源码拷贝下来。

    class NetClassLoader extends ClassLoader{
     private byte[] bb = null;
     //private String className = null;
     public NetClassLoader(){
      //super();
      super(ClassLoader.getSystemClassLoader().getParent());//让定义的类加载器与默认的系统类加载器平级
     }
     
     public Class<?> loadClass(String name) throws ClassNotFoundException {
      return loadClass(name, false);
     }
    // public Class<?> getLoadedClass(String className)throws ClassNotFoundException{
    //  Class c = null;
    //  
    //  FileInputStream fis;
    //  try {
    //   
    //   fis = new FileInputStream("bin\"+className+".class");
    //   int length = 0;
    //   length = fis.available();
    //   bb = new byte[length];
    //   fis.read(bb);
    //   fis.close();
    //  } catch (FileNotFoundException e) {
    //   throw new ClassNotFoundException("所要加载的类的字节码文件不存在");
    //  } catch (IOException e) {
    //   throw new RuntimeException("加载字节码文件时出错");
    //  }
    //
    //      c = findClass(className);
    //      return c;
    // }
     protected synchronized Class<?> loadClass(String className, boolean resolve)
     throws ClassNotFoundException
        {
     Class c = findLoadedClass(className);
     FileInputStream fis = null;
     if(c == null){
      try{
       c = super.loadClass(className, resolve);
      }catch(ClassNotFoundException e){
       
       try {
      
        fis = new FileInputStream("bin\"+className+".class");
        int length = 0;
        length = fis.available();
        bb = new byte[length];
        fis.read(bb);
        fis.close();
       } catch (FileNotFoundException fe) {
        throw new ClassNotFoundException("所要加载的类的字节码文件不存在");
       } catch (IOException ie) {
        throw new RuntimeException("加载字节码文件时出错");
       }
         c = defineClass(className,bb,0,bb.length);//createClass(className);
      }
     }
     if (resolve) {
         resolveClass(c);
     }
         return c;
        }
     
    // public NetClassLoader(byte[] b){
    //  bb = b;
    // }
     public Class createClass(String className){
      Class klass = defineClass(className,bb,0,bb.length);
      if(klass == null)
       System.out.println("是空的");
      return klass;
     }
    }

    使用java的自定义classloader机制实现类的动态加载。

    //自定义classloader
    public class StrategyClassLoader extends ClassLoader {
         
        //通过该方法实现类的加载
        public Class<BaseStrategy> loadStrategyClass(String name) throws FileNotFoundException, IOException {
        String classname = name.replace('.', File.separatorChar) + ".class";
        InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(classname);
        Class<BaseStrategy> cls = instantiateClass(name, is, is.available());
        return cls;
        }
     
        @SuppressWarnings("unchecked")
        private Class<BaseStrategy> instantiateClass(String name, InputStream fin, long len) throws IOException {
            byte[] raw = new byte[(int) len];
            try {
                fin.read(raw);
            } finally {
                fin.close();
            }
            return (Class<BaseStrategy>) defineClass(name, raw, 0, raw.length);
        }
     
    }
     
    //类加载器classloader的使用
    new StrategyClassLoader().loadStrategyClass("com.xxx.xxxx.DummyStrategy");

    注意:

    • 该classloader每次都重新读取class文件,实际使用时需要根据自己的需求决定是不是需要缓存。比如可以先检测class文件的时间戳是否变化再确定要不要通过new StrategyClassLoader来重新加载类,否则的话可以使用老的classloader并将之前加载过的class缓存起来以提高性能。

    • 你可以重写loadClass方法来实现目标,但这里我觉得没什么必要。

    • 是不是没更新一次类都要新建立一个classloader?是的,同个classloader中对于相同的类只能加载一次,如果想实现类的不断更新,必须建立新的classloader。

    • 建立这么多的classloader会不会导致内存或者其他资源问题?不会,classloader也只是一个普通的java对象,他一样会被GC垃圾回收掉。所以不用担心太多classloader导致资源不足问题,当然,我们尽可能的减少classloader的创建,毕竟类的加载也是挺耗时的操作。

  • 相关阅读:
    面试题3,求101-200之间有多少个素数,并且输出所有素数
    面试题2,兔子问题
    plsql 导入导出表数据与表结构
    plsql 的各个窗口区别
    oracle cmd命令
    ora-01017 用户名密码未登录
    PLSQL登录报错ORA-12154
    看oracle 的数据库位数
    plsql Developer 登录oracle出现 initialization error
    plsql dev 12 版下载地址
  • 原文地址:https://www.cnblogs.com/lukelook/p/10851201.html
Copyright © 2020-2023  润新知