• Java中的包扫描(工具)


    在现在好多应用场景中,我们需要得到某个包名下面所有的类, 包括我们自己在src里写的java类和一些第三方提供的jar包里的类,那么怎么来实现呢?

    今天带大家来完成这件事

    先分享代码

    1.这个类是一个抽象类,对类的处理交给用户,所以就有了dealClass的抽象方法。

      1 package com.mec.packscanner.core;
      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.URISyntaxException;
      8 import java.net.URL;
      9 import java.util.Enumeration;
     10 import java.util.jar.JarEntry;
     11 import java.util.jar.JarFile;
     12 
     13 public abstract class PackageScanner {
     14     public PackageScanner() {}
     15     
     16     public abstract void dealClass(Class<?> klass);
     17     
     18     //扫描一般的包。
     19     private void scanPackage(String packageName,File currentfile) {
     20         File[] filelist = currentfile.listFiles(new FileFilter() {
     21             //FileFilter是文件过滤器,源代码只写了一个accapt的抽象方法。
     22             @Override
     23             public boolean accept(File pathName) {
     24                 if(pathName.isDirectory()) {    //判断是否是目录
     25                     return true;
     26                 }
     27                 return pathName.getName().endsWith(".class");
     28             }
     29         });
     30         
     31         for(File file:filelist) {
     32             if(file.isDirectory()) {
     33                 scanPackage(packageName + "." + file.getName(),file);
     34             }else {
     35                 String fileName = file.getName().replace(".class", "");
     36                 String className = packageName + "." + fileName;
     37                 try {
     38                     Class<?> klass = Class.forName(className);//取出所有的类
     39                     if(klass.isAnnotation() //不扫描注解类、枚举类、接口和八大基本类型。
     40                             ||klass.isEnum()
     41                             ||klass.isInterface()
     42                             ||klass.isPrimitive()) {
     43                         continue;
     44                     }
     45                     dealClass(klass);
     46                 } catch (ClassNotFoundException e) {
     47                     e.printStackTrace();
     48                 }
     49             }
     50         }
     51     }
     52     
     53     //扫描jar包方法。
     54     private void scanPackage(URL url) throws IOException {
     55         JarURLConnection urlConnection = (JarURLConnection) url.openConnection();
     56         JarFile jarfile = urlConnection.getJarFile();
     57         Enumeration<JarEntry> jarEntries = jarfile.entries();
     58         while(jarEntries.hasMoreElements()) {
     59             JarEntry jarEntry = jarEntries.nextElement();
     60             String jarName = jarEntry.getName();
     61             if(!jarName.endsWith(".class")) {
     62                 continue;
     63             }
     64             String className = jarName.replace(".class", "").replaceAll("/", ".");
     65             
     66             try {
     67                 Class<?> klass = Class.forName(className);
     68                 if (klass.isAnnotation() 
     69                         || klass.isInterface()
     70                         || klass.isEnum()
     71                         || klass.isPrimitive()) {
     72                     continue;
     73                 }
     74                 dealClass(klass);
     75             } catch (ClassNotFoundException e) {
     76                 e.printStackTrace();
     77             }
     78         }
     79     }
     80     
     81     //用类名扫描
     82     public void packageScan(Class<?> klass) {
     83         packageScan(klass.getPackage().getName());
     84     }
     85     
     86     //用包名进行扫描
     87     public void packageScan(String packageName) {
     88         String packOpperPath = packageName.replace(".","/");
     89         
     90         //线程上下文类加载器得到当前的classpath的绝对路径.(动态加载资源)
     91         ClassLoader classloader = Thread.currentThread().getContextClassLoader();
     92         try {
     93             //(Thread.currentThread().getContextClassLoader().getResource(""))
     94             //(来得到当前的classpath的绝对路径的URI表示法。)
     95             Enumeration<URL> resources = classloader.getResources(packOpperPath);
     96             while(resources.hasMoreElements()) {
     97                 //先获得本类的所在位置                
     98                 URL url = resources.nextElement();
     99                 
    100                 //url.getProtocol()是获取URL的HTTP协议。
    101                 if(url.getProtocol().equals("jar")) {
    102                 //判断是不是jar包
    103                     scanPackage(url);
    104                 }else {
    105                     //此方法不会自动将链接中的非法字符转义。
    106                     //而在File转化成URI的时候,会将链接中的特殊字符如#或!等字符进行编码。
    107                     File file = new File(url.toURI());
    108                     if(!file.exists()) {
    109                         continue;
    110                     }
    111                     scanPackage(packageName,file);
    112                 }
    113             }
    114         } catch (IOException e) {
    115             e.printStackTrace();
    116         } catch (URISyntaxException e) {
    117             e.printStackTrace();
    118         }
    119     }
    120 }

    这个是抽象类,对于扫描,我们只提供扫描的工具,而定义抽象方法是往外接,通过使用者的使用来决定用类名还是包名。

    对于jar包的扫描,可以进JarURLConnection类和JarFile类的源码中可以理解。

     2.定义测试类,它是扫描jar包的:

     1 package com.mec.packscanner.test;
     2 
     3 import com.mec.packscanner.core.PackageScanner;
     4 
     5 public class Test {
     6 
     7     public static void main(String[] args) {
     8         new PackageScanner() {
     9             
    10             @Override
    11             public void dealClass(Class<?> klass) {
    12                 System.out.println(klass.getName());
    13                 
    14             }
    15         }.packageScan("com.mec.xml_view.core");;
    16     }
    17 
    18 }

    结果:

     从结果我们可以看出把jar包中的每一个class都输出了,匿名内部类都被扫描出来了。

    我们来看看普通包的结果吧:

     1 package com.mec.packscanner.test;
     2 
     3 import com.mec.packscanner.core.PackageScanner;
     4 
     5 public class Test {
     6 
     7     public static void main(String[] args) {
     8         new PackageScanner() {
     9             
    10             @Override
    11             public void dealClass(Class<?> klass) {
    12                 System.out.println(klass.getName());
    13                 
    14             }
    15         }.packageScan("com.mec.server_client.core");;
    16     }
    17 
    18 }

    对普通的包也是,这个例子除了接口,其他的都被扫描出来了。

    若有漏洞,请指正!感谢您的阅读。

  • 相关阅读:
    [Powershell]导出指定的定时计划任务
    [Powershell]发布基于.NET Framework的WebAPI和Job控制台程序项目
    [Powershell]使用Msbuild构建基于.NET Framework的WebAPI项目
    [最新].NET Core ORM 开源项目一览,持续更新
    【最新】Xmanager Power Suite 6.0 Build 0017
    Git抽取版本之间的差异,打包解压
    PuppeteerSharp+AngleSharp的爬虫实战之汽车之家数据抓取
    PostgreSql之在group by查询下拼接列字符串
    同事问如何判断同花顺,我用javascript的二维数组写了个简易demo
    Gitlab定义安全变量遇到无法转义的字符——感叹号
  • 原文地址:https://www.cnblogs.com/youdiaodaxue16/p/9813087.html
Copyright © 2020-2023  润新知