java读取指定package下的所有class

来源:互联网 发布:看韩剧的软件 编辑:程序博客网 时间:2024/04/30 01:07

之前在看spring注解的时候,有看到再配置文件里面定义component scan package就能自动扫描对应包下面的class,然后根据注解生成相应的bean。自己对这个功能很好奇,就搜了下,找到了实现的关键代码,记录下。后续再对这段代码深入学习。

Java代码 复制代码
  1. package com.bch.scanner;   
  2.   
  3. import java.io.File;   
  4. import java.io.FileFilter;   
  5. import java.io.IOException;   
  6. import java.net.JarURLConnection;   
  7. import java.net.URL;   
  8. import java.net.URLDecoder;   
  9. import java.util.Enumeration;   
  10. import java.util.LinkedHashSet;   
  11. import java.util.Set;   
  12. import java.util.jar.JarEntry;   
  13. import java.util.jar.JarFile;   
  14.   
  15. /**  
  16.  * 类扫描器,扫描给定包及其子包中的所有类  
  17.  * @author abao  
  18.  *  
  19.  */  
  20. public class ClassScanner {   
  21.   
  22. /**  
  23.  * 从包package中获取所有的Class  
  24.  *   
  25.  * @param pack  
  26.  * @return  
  27.  */  
  28. public static Set<Class<?>> getClasses(String pack) {   
  29.   
  30.   // 第一个class类的集合   
  31.   Set<Class<?>> classes = new LinkedHashSet<Class<?>>();   
  32.   // 是否循环迭代   
  33.   boolean recursive = true;   
  34.   // 获取包的名字 并进行替换   
  35.   String packageName = pack;   
  36.   String packageDirName = packageName.replace('.''/');   
  37.   // 定义一个枚举的集合 并进行循环来处理这个目录下的things   
  38.   Enumeration<URL> dirs;   
  39.   try {   
  40.     dirs = Thread.currentThread()   
  41.     .getContextClassLoader()   
  42.     .getResources(packageDirName);   
  43.     // 循环迭代下去   
  44.     while (dirs.hasMoreElements()) {   
  45.      // 获取下一个元素   
  46.       URL url = dirs.nextElement();   
  47.      // 得到协议的名称   
  48.       String protocol = url.getProtocol();   
  49.      // 如果是以文件的形式保存在服务器上   
  50.       if ("file".equals(protocol)) {   
  51.        System.err.println("file类型的扫描");   
  52.        // 获取包的物理路径   
  53.         String filePath = URLDecoder.decode(url.getFile(), "UTF-8");   
  54.        // 以文件的方式扫描整个包下的文件 并添加到集合中   
  55.         findAndAddClassesInPackageByFile(packageName,    
  56.                     filePath, recursive, classes);   
  57.      } else if ("jar".equals(protocol)) {   
  58.        // 如果是jar包文件   
  59.         // 定义一个JarFile   
  60.        System.err.println("jar类型的扫描");   
  61.        JarFile jar;   
  62.        try {   
  63.          // 获取jar   
  64.          jar = ((JarURLConnection) url.openConnection()).getJarFile();   
  65.          // 从此jar包 得到一个枚举类   
  66.           Enumeration<JarEntry> entries = jar.entries();   
  67.          // 同样的进行循环迭代   
  68.           while (entries.hasMoreElements()) {   
  69.            // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件  
  70.              JarEntry entry = entries.nextElement();   
  71.             String name = entry.getName();   
  72.             // 如果是以/开头的   
  73.              if (name.charAt(0) == '/') {   
  74.               // 获取后面的字符串   
  75.                 name = name.substring(1);   
  76.             }   
  77.             // 如果前半部分和定义的包名相同   
  78.               if (name.startsWith(packageDirName)) {   
  79.             int idx = name.lastIndexOf('/');   
  80.             // 如果以"/"结尾 是一个包   
  81.               if (idx != -1) {   
  82.               // 获取包名 把"/"替换成"."   
  83.               packageName = name.substring(0, idx).replace('/''.');   
  84.              }   
  85.              // 如果可以迭代下去 并且是一个包   
  86.                if ((idx != -1) || recursive) {   
  87.                // 如果是一个.class文件 而且不是目录   
  88.                  if (name.endsWith(".class")&& !entry.isDirectory()) {   
  89.                  // 去掉后面的".class" 获取真正的类名   
  90.                    String className = name.substring(   
  91.                               packageName.length() + 1, name.length() - 6);   
  92.                  try {   
  93.                    // 添加到classes   
  94.                    classes.add(Class.forName(packageName + '.'+ className));   
  95.                  } catch (ClassNotFoundException e) {   
  96.                    // log   
  97.                    // .error("添加用户自定义视图类错误 找不到此类的.class文件");  
  98.                    e.printStackTrace();   
  99.                  }   
  100.                }   
  101.              }   
  102.            }   
  103.          }   
  104.        } catch (IOException e) {   
  105.          // log.error("在扫描用户定义视图时从jar包获取文件出错");   
  106.          e.printStackTrace();   
  107.        }   
  108.      }   
  109.     }   
  110.   } catch (IOException e) {   
  111.     e.printStackTrace();   
  112.   }   
  113.   
  114. return classes;   
  115. }   
  116.        
  117. /**  
  118.  * 以文件的形式来获取包下的所有Class  
  119.  *   
  120.  * @param packageName  
  121.  * @param packagePath  
  122.  * @param recursive  
  123.  * @param classes  
  124. */  
  125. public static void findAndAddClassesInPackageByFile(String packageName,   
  126.     String packagePath, final boolean recursive, Set<Class<?>> classes) {   
  127. // 获取此包的目录 建立一个File   
  128. File dir = new File(packagePath);   
  129. // 如果不存在或者 也不是目录就直接返回   
  130. if (!dir.exists() || !dir.isDirectory()) {   
  131.   // log.warn("用户定义包名 " + packageName + " 下没有任何文件");   
  132.   return;   
  133. }   
  134. // 如果存在 就获取包下的所有文件 包括目录   
  135. File[] dirfiles = dir.listFiles(new FileFilter() {   
  136.   // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)  
  137.   public boolean accept(File file) {   
  138.     return (recursive && file.isDirectory())||    
  139.                     (file.getName().endsWith(".class"));   
  140. }   
  141. });   
  142. // 循环所有文件   
  143. for (File file : dirfiles) {   
  144. // 如果是目录 则继续扫描   
  145. if (file.isDirectory()) {   
  146. findAndAddClassesInPackageByFile(packageName + "."  
  147.         + file.getName(), file.getAbsolutePath(), recursive,   
  148.         classes);   
  149. else {   
  150. // 如果是java类文件 去掉后面的.class 只留下类名   
  151. String className = file.getName().substring(0,   
  152.                     file.getName().length() - 6);   
  153. try {   
  154. // 添加到集合中去   
  155. //classes.add(Class.forName(packageName + '.' + className));  
  156. //经过回复同学的提醒,这里用forName有一些不好,会触发static方法,   
  157. //没有使用classLoader的load干净   
  158. classes.add(Thread.currentThread()   
  159.         .getContextClassLoader()   
  160.         .loadClass(packageName + '.' + className));     
  161. catch (ClassNotFoundException e) {   
  162. // log.error("添加用户自定义视图类错误 找不到此类的.class文件");   
  163. e.printStackTrace();   
  164. }   
  165. }   
  166. }   
  167. }   
  168.   
  169. }  

 

 

自己直接拿过来用了,可以扫描package对应的子package,不过是对当前classLoad下的所有jar进行扫描的。

0 0