java URLClassLoader used to access the external jar package java class

Many times we write Java programs are sub-module, a very good extension mechanism that we can add plug-ins for our own java classes to run out someday we may develop in the future class, the following call these plug-in class .

Below is a simple realization:

Class A as the main program entry, which entry includes the execution of a program (main) function. Then the main function by an external profile, and by an external profile, information (which jar package, jar package is located in a specific path) we can get the plugin class, and then obtain an instance of a particular class jar package to to complete the work. This is likely to be outside the jar package jar package, written our own, where we put it, he can himself find it? I tried many times, unless specific directory, put in class_path can perform successfully, otherwise an exception ClassNotFoundException only one newspaper, you could not find the class. Another method, however, is to extract the jar package where the package directory run the jar, so that the corresponding class may be obtained by the class_path. But it would seem unprofessional, java things are written jar package ah, their feelings. Claspath put, you can not write every time a new jar packages are configured it again!

So there have been the following solution:

To learn the meaning of the solution, we must first understand the class loading mechanism of java. As we all know, if you want to execute the program must be loaded into memory to successfully execute. java program is not executable, done by many independent class files. So the java class loader is a single foreign completed. This also requires us to take a brief look of java class loader loading mechanism.

java program started, the first encounter is a classloader bootstrap classloader, the classloader is written in c ++ language, to finish loading java in core classes through him. The second is the classloader extension classloader, loading a jre / lib directory ext directory a jar. Then the third is the system classloader, also referred to as an application loader is responsible for loading completed or -classpath ClassPath system global variables in the class. System.out.println (System.getProperty ( "java.class.path")); classpath configuration can be obtained, i.e. system classloader loaded class, the fourth class loader may be user-defined loader customize load class. The loading process is usually a class like this by the parent loader tries to find the current class loader, if you did not find his father loader tries to load until the final bootstrap classloader, if it is not found, then start from the load class down. The aim is to prevent the system to cover the class custom class, if there is no such mechanism is prone to this sort of joke, wrote a String class, then when the new string is to write the String class, so Compare fun.

1. URLClassLoader their own definition of the object to load an external jar package, the situation is no longer present other jar package jar package for inside, that is only resolved .class file:

private static void test1() {  
 Path String = " D: \\ test.jar " ; // external jar package path   
 the Set <Class <= >> classes? New new LinkedHashSet <Class <>> ();? // All Class object   
 Map <Class < ?>, the annotation []> = classAnnotationMap new new the HashMap <Class <>, the annotation []> ();? // annotation objects on each Class object   
 ? Map <Class <>, Map <Method, annotation [] >> = classMethodAnnoMap new new ? the HashMap <Class <>, the Map <method,, the annotation [] >> (); // annotation objects on each Class object for each method   
 the try {  
  JarFile jarFile = new JarFile(new File(path));  
  URL url = new URL("file:" + path);  
  Loader ClassLoader = new new the URLClassLoader ( new new the URL [] {} URL); // classLoader own class definition, is also applied to the external load paths in the path, the path to the system to load the object   
  the Enumeration <the JarEntry for> ES = jarFile.entries ();  
   the while (es.hasMoreElements ()) {  
   JarEntry jarEntry = (JarEntry) es.nextElement ();  
   Name String = jarEntry.getName ();  
    IF (! Name = null && name.endsWith ( " .class " )) { // only resolve the .class file does not resolve inside a jar  
     // default to the system has been defined PathFinder object can not be used for external jar package  
     // Class <?> c = Thread.currentThread (). getContextClassLoader (). loadClass (name.replace ( "/", "."). substring (0, name.length () -. 6));   
    Class C = loader.loadClass (name.replace (<?> " / " , " . " ) .substring ( 0 , name.length () - . 6 ));// Loader define their own path can be found   
    System. OUT.println(c);  
    classes.add(c);  
    Annotation [] classAnnos = c.getDeclaredAnnotations ();  
    classAnnotationMap.put (c, classAnnos);  
    Method[] classMethods = c.getDeclaredMethods();  
    Map<Method, Annotation[]> methodAnnoMap = new HashMap<Method, Annotation[]>();  
    for(int i = 0;i<classMethods.length;i++){  
     Annotation[] a = classMethods[i].getDeclaredAnnotations();  
     methodAnnoMap.put(classMethods[i], a);  
    }  
    classMethodAnnoMap.put(c, methodAnnoMap);  
   }  
  }  
  System.out.println(classes.size());  
 } catch (IOException e) {  
  e.printStackTrace ();  
 } catch (ClassNotFoundException e) {  
  e.printStackTrace ();  
 }  
}
 In this case more than can be written in other project items in test method, it is usually the most commonly used, if the .class file when there are dependent on other objects jar bag when you want to copy the jar package to write this project test methods and buildPath, when otherwise reported abnormal operation will not find Class object.

2. The second scenario is for the Class object to load jar package jar package inside, there is a method of reading a properties file.

private static void test2() {  
  Path String = " D: \\ test.jar " ; // This jar jar package bag there are other   
  the try {  
   JarFile jarfile = new JarFile(new File(path));  
   Enumeration<JarEntry> es = jarfile.entries();  
   while (es.hasMoreElements()) {  
    JarEntry je = es.nextElement();  
    String name = je.getName();  
    if(name.endsWith(".jar")){//读取jar包里的jar包  
     File f = new File(name);  
     JarFile j = new JarFile(f);  
     Enumeration<JarEntry> e = j.entries();  
     while (e.hasMoreElements()) {  
      JarEntry jarEntry = (JarEntry) e.nextElement();  
      System.out.println(jarEntry.getName());  
      //.........接下去和上面的方法类似  
     }  
    }  
//    System.out.println(je.getName());  
    if(je.getName().equals("entity_pk.properties")){  
     InputStream inputStream = jarfile.getInputStream(je);  
     Properties properties = new Properties();  
     properties.load(inputStream);  
     Iterator<Object> ite = properties.keySet().iterator();  
     while (ite.hasNext()) {  
      Object key = ite.next();  
      System.out.println(key + " : " +properties.get(key));  
     }  
    }  
   }  
  } catch (IOException e) {  
   e.printStackTrace();  
  }  
 }

3.第三种情况是在该项目下获取某个包的Class对象,当然了,测试方法是在该项目下写的(这样classLoader就直接可以知道对象了,不需要再自定义URLClassLoader了,用Thread.currentThread().getContextClassLoader().loadClass(.....)就可以直接获得Class对象了,回去ClassPath下找,System.out.print(System.getProperty("java.class.path"))就可以找到classPath路径)。

private static Set<Class<?>>  getclass() {  
  Set<Class<?>> classes = new LinkedHashSet<Class<?>>();  
  boolean flag = true;//是否循环迭代  
   
  String packName = "com.yk.framework.db";  
//  String packName = "org.jdom";  
  String packDir = packName.replace(".", "/");  
  Enumeration<URL> dir;  
  try {  
   dir = Thread.currentThread().getContextClassLoader().getResources(packDir);  
   while(dir.hasMoreElements()){  
    URL url = dir.nextElement();  
    System.out.println("url:***" + url);  
    String protocol = url.getProtocol();//获得协议号  
    if("file".equals(protocol)){  
     System.err.println("file类型的扫描");  
     String filePath = URLDecoder.decode(url.getFile(), "UTF-8");  
     System.out.println("filePath :" + filePath);  
     findAndAddClassesInPackageByFile(packName, filePath,flag,classes);  
    }else if("jar".equals(protocol)){  
     System.err.println("jar类型扫描");  
     JarFile jar;  
     jar = ((JarURLConnection)url.openConnection()).getJarFile();  
     Enumeration<JarEntry> entries = jar.entries();  
     while(entries.hasMoreElements()){  
      JarEntry entry = entries.nextElement();  
      String name = entry.getName();  
      System.out.println(">>>>:" + name);  
      //......  
     }  
       
    }  
      
   }  
     
  } catch (IOException e) {  
   e.printStackTrace();  
  }  
  System.out.println(classes.size());  
  return classes;  
    
 }

下面上第二段代码

private static void findAndAddClassesInPackageByFile(String packName, String filePath, final boolean flag, Set<Class<?>> classes) {  
 File dir = new File(filePath);  
 if( !dir.exists() || !dir.isDirectory()){  
  System.out.println("此路径下没有文件");  
  return;  
 }  
 File[] dirfiles = dir.listFiles(new FileFilter(){  
  @Override  
  public boolean accept(File pathname) {  
   return flag && pathname.isDirectory() || pathname.getName().endsWith(".class");  
  }  
 });  
 for (File file : dirfiles) {  
  if(file.isDirectory()){//如果是目录,继续扫描  
   findAndAddClassesInPackageByFile(packName + "." + file.getName(),file.getAbsolutePath(),flag,classes);  
  }else{//如果是文件  
   String className = file.getName().substring(0,file.getName().length() - 6);  
   System.out.println("类名:" +className);  
   try {  
    classes.add(Thread.currentThread().getContextClassLoader().loadClass(packName + "." + className));  
   } catch (ClassNotFoundException e) {  
    e.printStackTrace();  
   }  
  }  
 }  
}

补充:

4.读取jar包中的entity_pk.properties键值对到项目本地entity_pk.properties文件中

/** 
 * 读取jar包中的entity_pk.properties键值对到项目本地entity_pk.properties文件中 
 */  
private static void test2() {  
    String path = "D:\\test.jar";  
    try {  
        JarFile jarFile = new JarFile(new File(path));  
        Enumeration<JarEntry> es = jarFile.entries();  
        while (es.hasMoreElements()) {  
            JarEntry jarEntry = (JarEntry) es.nextElement();  
            String name = jarEntry.getName();  
            if(name.equals("entity_pk.properties")){  
                InputStream inputStream = new FileInputStream(name);  
                Properties prop = new Properties();  
                prop.load(inputStream);//先load本地的entity_pk.propertoes文件  
                InputStream inputStream2 = jarFile.getInputStream(jarEntry);//获得jar包entity_pk.propertoes文件流  
                Properties prop2 = new Properties();  
                prop2.load(inputStream2);  
                Enumeration<Object> ks = prop2.keys();  
                OutputStream out = new FileOutputStream(name);  
                while (ks.hasMoreElements()) {  
                    String key =  (String)ks.nextElement();  
                    System.out.println(key + " : " +prop2.getProperty(key));  
                    prop.setProperty(key, prop2.getProperty(key));//把jar包entity_pk.properties键值对放入本地  
                }  
                prop.store(out,"");  
            }  
        }  
          
    } catch (IOException e) {  
        e.printStackTrace();  
    }  
      
}

5.读写db_config.xml文件

/** 
 * 读写db_config.xml文件 
 */  
private static void test3() {  
    String path = "D:\\test.jar";  
    try {  
        JarFile jarFile = new JarFile(new File(path));  
        Enumeration<JarEntry> es = jarFile.entries();  
        while (es.hasMoreElements()) {  
            JarEntry jarEntry = (JarEntry) es.nextElement();  
            String name = jarEntry.getName();  
            if(name.equals("db_config.xml")){  
                InputStream inputStream = jarFile.getInputStream(jarEntry);  
                SAXBuilder builder = new SAXBuilder();  
                Document doc = null;  
                try {  
                    doc = builder.build(inputStream);  
                    if(doc != null){  
                        Element e = doc.getRootElement();  
                        Element proxool = e.getChild("proxool");  
                        List<Element> children = proxool.getChildren();  
                        for (Element element : children) {  
                            System.out.println(element.getText());  
                        }  
                        Element s = new Element("test");  
                        s.addContent("test");  
                        proxool.addContent(s);  
                        XMLOutputter outputter = new XMLOutputter();  
                        outputter.output(doc, new FileOutputStream("config/db_config.xml"));  
                    }  
                } catch (JDOMException e) {  
                    e.printStackTrace();  
                }finally{  
                    if(inputStream != null){  
                        inputStream.close();  
                    }  
                }  
                  
            }  
              
        }  
          
    } catch (IOException e) {  
        e.printStackTrace();  
    }  
}

 

Guess you like

Origin www.cnblogs.com/itboys/p/11011585.html