java如何实现一个扫描包的工具类

发布时间:2021-04-17 14:37:17 作者:小新
来源:亿速云 阅读:294

小编给大家分享一下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

以上是“java如何实现一个扫描包的工具类”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

推荐阅读:
  1. 使用Java怎么实现一个分页工具类
  2. java怎么实现一个邮件通知工具类

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:Java怎么实现的文件上传下载工具类

下一篇:Java怎么实现分解任意输入数的质因数算法

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》