java实现一个扫描包的工具类实例代码

前言

在很多的实际场景中,我们需要得到某个包名下面所有的类,比如我们在使用SpringMVC的时候,知道SpringMVC可以扫描指定包下的所有类,在平时的开发中,我们也有这样的场景,所以今天写一个扫描包的工具类,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。

代码如下:

package com.gujin.utils;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class HQScanPackage
{
 /** 是否循环迭代 **/
 boolean recursive = true;
 /** 包名集合 **/
 private List<String> packageNames = new ArrayList<String>();
 /** 过滤器 **/
 private HQScanPackageFilter filter = null;
 /** 监听器 **/
 private HQScanPackageListener listener = null;

 /**
 * 是否循环迭代
 *
 * @return
 */
 public boolean isRecursive()
 {
  return recursive;
 }

 /**
 * 设置是否循环迭代
 *
 * @param recursive
 */
 public void setRecursive(boolean recursive)
 {
  this.recursive = recursive;
 }

 /**
 * 获得过滤器
 *
 * @return
 */
 public HQScanPackageFilter getFilter()
 {
  return filter;
 }

 /**
 * 设置过滤器
 *
 * @param filter
 */
 public void setFilter(HQScanPackageFilter filter)
 {
  this.filter = filter;
 }

 /**
 * 获得监听器
 *
 * @return
 */
 public HQScanPackageListener getListener()
 {
  return listener;
 }

 /**
 * 设置监听器
 *
 * @param listener
 */
 public void setListener(HQScanPackageListener listener)
 {
  this.listener = listener;
 }

 /**
 * 添加扫描包
 *
 * @param packageName
 */
 public void addPackage(String packageName)
 {
  if (packageName == null || !packageName.matches("[\\w]+(\\.[\\w]+)*"))
  {
   throw new IllegalArgumentException("非法包名.");
  }
  this.packageNames.add(packageName);
 }

 /**
 * 清空扫描包
 */
 public void clearPackage()
 {
  this.packageNames.clear();
 }

 /**
 * 扫描
 */
 public void scan()
 {
  for (String packageName : packageNames)
  {
   scan(packageName);
  }
 }

 /**
 * 是否接受
 *
 * @param clazz
 * @return
 */
 private boolean accept(Class<?> clazz)
 {
  if (this.filter != null)
  {
   return this.filter.accept(clazz);
  }
  return true;
 }

 /**
 * 触发扫描到合法类
 *
 * @param clazz
 * @return
 */
 private void trrigerOnScanClass(Class<?> clazz)
 {
  if (this.listener != null)
  {
   this.listener.onScanClass(clazz);
  }
 }

 /**
 * 扫描到类
 *
 * @param clazz
 * @return
 */
 private void onScanClass(Class<?> clazz)
 {
  if (accept(clazz))
  {
   trrigerOnScanClass(clazz);
  }
 }

 /**
 * 从包package中获取所有的Class
 *
 * @param packageName
 * @return
 */
 private void scan(String packageName)
 {
  // 获取包的名字 并进行替换
  String packageDirName = packageName.replace('.', '/');
  // 定义一个枚举的集合 并进行循环来处理这个目录下的things
  Enumeration<URL> dirs = null;
  try
  {
   dirs = Thread.currentThread().getContextClassLoader()
    .getResources(packageDirName);
   // 循环迭代下去
   while (dirs.hasMoreElements())
   {
   // 获取下一个元素
   URL url = dirs.nextElement();
   // 得到协议的名称
   String protocol = url.getProtocol();
   // 如果是以文件的形式保存在服务器上
   if ("file".equals(protocol))
   {
    // 获取包的物理路径
    String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
    // 以文件的方式扫描整个包下的文件 并添加到集合中
    findAndAddClassesInPackageByFile(packageName, filePath);
   }
   else if ("jar".equals(protocol))
   {
    // 如果是jar包文件
    // 定义一个JarFile
    JarFile jar = null;
    try
    {
     // 获取jar
     jar = ((JarURLConnection) url.openConnection()).getJarFile();
     // 从此jar包 得到一个枚举类
     Enumeration<JarEntry> entries = jar.entries();
     // 同样的进行循环迭代
     while (entries.hasMoreElements())
     {
      // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
      JarEntry entry = entries.nextElement();
      String name = entry.getName();
      // 如果是以/开头的
      if (name.charAt(0) == '/')
      {
      // 获取后面的字符串
      name = name.substring(1);
      }
      // 如果前半部分和定义的包名相同
      if (name.startsWith(packageDirName))
      {
      int idx = name.lastIndexOf('/');
      // 如果以"/"结尾 是一个包
      if (idx != -1)
      {
       // 获取包名 把"/"替换成"."
       packageName = name.substring(0, idx).replace('/',
         '.');
      }
      // 如果可以迭代下去 并且是一个包
      if ((idx != -1) || recursive)
      {
       // 如果是一个.class文件 而且不是目录
       if (name.endsWith(".class") && !entry.isDirectory())
       {
        // 去掉后面的".class" 获取真正的类名
        String className = name.substring(
         packageName.length() + 1,
         name.length() - 6);
        try
        {
         // 添加到classes
         // 使用Class.forName会触发类静态方法
         Class<?> clazz = Thread.currentThread()
          .getContextClassLoader().loadClass(
            packageName + '.' + className);
         onScanClass(clazz);
        }
        catch (ClassNotFoundException e)
        {
         System.err.println("加载类出错");
        }
       }
      }
      }
     }
    }
    catch (IOException e)
    {
     System.err.println("在扫描用户定义视图时从jar包获取文件出错");
     e.printStackTrace();
    }
   }
   }
  }
  catch (IOException e)
  {
   System.err.println("扫描出错");
   e.printStackTrace();
  }
 }

 /**
 * 以文件的形式来获取包下的所有Class
 *
 * @param packageName
 * @param packagePath
 */
 private void findAndAddClassesInPackageByFile(String packageName,
   String packagePath)
 {
  // 获取此包的目录 建立一个File
  File dir = new File(packagePath);
  // 如果不存在或者 也不是目录就直接返回
  if (!dir.exists() || !dir.isDirectory())
  {
   System.err.println("用户定义包名 " + packageName + " 下没有任何文件");
   return;
  }
  // 如果存在 就获取包下的所有文件 包括目录
  File[] dirfiles = dir.listFiles(new FileFilter()
  {
   // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
   public boolean accept(File file)
   {
   return (recursive && file.isDirectory())
     || (file.getName().endsWith(".class"));
   }
  });
  // 循环所有文件
  for (File file : dirfiles)
  {
   // 如果是目录 则继续扫描
   if (file.isDirectory())
   {
   findAndAddClassesInPackageByFile(packageName + "." + file.getName(),
     file.getAbsolutePath());
   }
   else
   {
   // 如果是java类文件 去掉后面的.class 只留下类名
   String className = file.getName().substring(0,
     file.getName().length() - 6);
   try
   {
    Class<?> clazz = Thread.currentThread().getContextClassLoader()
      .loadClass(packageName + '.' + className);
    onScanClass(clazz);
   }
   catch (ClassNotFoundException e)
   {
    System.err.println("添加用户自定义视图类错误 找不到此类的.class文件");
    e.printStackTrace();
   }
   }
  }
 }

 /**
 * 扫描包过滤器
 *
 * @author jianggujin
 *
 */
 public static interface HQScanPackageFilter
 {
  /**
  * 是否接受
  *
  * @param clazz
  * @return
  */
  public boolean accept(Class<?> clazz);
 }

 /**
 * 扫描包监听
 *
 * @author jianggujin
 *
 */
 public static interface HQScanPackageListener
 {
  /**
  * 扫描到合法类执行
  *
  * @param clazz
  */
  public void onScanClass(Class<?> clazz);
 }

 public static void main(String[] args)
 {
  HQScanPackage scanPackage = new HQScanPackage();
  scanPackage.addPackage(HQScanPackage.class.getPackage().getName());
  scanPackage.setFilter(new HQScanPackageFilter()
  {

   @Override
   public boolean accept(Class<?> clazz)
   {
   return true;
   }
  });
  scanPackage.setListener(new HQScanPackageListener()
  {

   @Override
   public void onScanClass(Class<?> clazz)
   {
   System.out.println(clazz);
   }
  });
  scanPackage.scan();
 }
}

运行可以得到如下结果:

class com.gujin.utils.HQScanPackage$1
class com.gujin.utils.HQScanPackage$2
class com.gujin.utils.HQScanPackage$3
interface com.gujin.utils.HQScanPackage$HQScanPackageFilter
interface com.gujin.utils.HQScanPackage$HQScanPackageListener
class com.gujin.utils.HQScanPackage 

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • java实现一个扫描包的工具类实例代码

    前言 在很多的实际场景中,我们需要得到某个包名下面所有的类,比如我们在使用SpringMVC的时候,知道SpringMVC可以扫描指定包下的所有类,在平时的开发中,我们也有这样的场景,所以今天写一个扫描包的工具类,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 代码如下: package com.gujin.utils; import java.io.File; import java.io.FileFilter; import java.io.IOException; imp

  • Java语言描述MD5加密工具类实例代码

    编程中经常有用到MD5加密的情况,Java语言并没有像PHP一样提供原生的MD5加密字符串的函数,需要MD5加密的时候,往往需要自己写. 代码如下: import java.security.MessageDigest; public class MD5 { //公盐 private static final String PUBLIC_SALT = "demo" ; //十六进制下数字到字符的映射数组 private final static String[] hexDigits =

  • Android快速开发系列 10个常用工具类实例代码详解

    打开大家手上的项目,基本都会有一大批的辅助类,今天特此整理出10个基本每个项目中都会使用的工具类,用于快速开发~~在此感谢群里给我发项目中工具类的兄弟/姐妹~ 1.日志工具类L.java package com.zhy.utils; import android.util.Log; /** * Log统一管理类 * * * */ public class L { private L() { /* cannot be instantiated */ throw new UnsupportedOpe

  • Android常用正则表达式验证工具类(实例代码)

    东西不多,但一般项目够用了. public class RegularUtil { //身份证 public static final String REGEX_ID_CARD = "^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9]|X)$"; //验证邮箱 public static final String REGEX_EMAIL = "^([a-z0-9A-Z]+[-|\\

  • Java实现的DES加密解密工具类实例

    本文实例讲述了Java实现的DES加密解密工具类.分享给大家供大家参考,具体如下: 一个工具类,很常用,不做深入研究了,那来可直接用 DesUtil.java package lsy; import java.security.Key; import java.security.SecureRandom; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; imp

  • java身份证合法性校验工具类实例代码

    1.身份证规则 计算方法(来源百度) 将前面的身份证号码17位数分别乘以不同的系数.从第一位到第十七位的系数分别为:7-9-10-5-8-4-2-1-6-3-7-9-10-5-8-4-2. 将这17位数字和系数相乘的结果相加. 用加出来和除以11,看余数是多少? 余数只可能有0-1-2-3-4-5-6-7-8-9-10这11个数字.其分别对应的最后一位身份证的号码为1-0-X -9-8-7-6-5-4-3-2.(即余数0对应1,余数1对应0,余数2对应X-) 通过上面得知如果余数是3,就会在身份

  • 一个最简单的vbs类实例代码

    class CFoo     sub PrintHello()         response.Write "Hello World!"     end sub end class dim obj set obj = new CFoo  call obj.PrintHello set obj = nothing

  • Android编程实现的身份证、车牌号正则验证工具类实例

    本文实例讲述了Android编程实现的身份证.车牌号正则验证工具类.分享给大家供大家参考,具体如下: /** * 正则表达式验证工具类(验证身份证.车牌号等) * * @author chenlin * */ public class ValidateUtil { /** * 验证str是否为正确的身份证格式 * * @param str * @return */ public static boolean isIdentityCard(EditText view) { boolean flag

  • Java实现操作JSON的便捷工具类完整实例【重写Google的Gson】

    本文实例讲述了Java实现操作JSON的便捷工具类.分享给大家供大家参考,具体如下: 对于JSON数据格式的处理,自开发Java以来,已用过多种JSON的开源工具,用得最好,也用得最High的恐怕要属Google的Gson了. 特别为它写了一个工具类,放入常备工具中,方便使用.下面是为GSON 1.5版本重写的工具类. 依赖包: slf4j-api-1.6.0.jar slf4j-log4j12-1.6.0.jar log4j-1.2.15.jar gson-1.5.jar /** * Copy

  • Java日期操作方法工具类实例【包含日期比较大小,相加减,判断,验证,获取年份等】

    本文实例讲述了Java日期操作方法工具类.分享给大家供大家参考,具体如下: package com.gcloud.common; import org.apache.http.util.TextUtils; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.regex.Patte

随机推荐