使用java怎么扫描指定包下的类

Posted 跨链技术践行者

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用java怎么扫描指定包下的类相关的知识,希望对你有一定的参考价值。

Java可以用来干什么

Java主要应用于:1. web开发;2. android开发;3. 客户端开发;4. 网页开发;5. 企业级应用开发;6. Java大数据开发;7.游戏开发等。

src下面的类如何获取:

首先,比较简单的是得到我们自己写的类,我们先来完成这个,

项目的结构图如下:

我故意创建了这么个比较复杂的项目结构,现在我们就来获取com.baibin包下所有的类,并且打印他们,代码如下:

import org.junit.Test;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class Main 
    List<String> classPaths = new ArrayList<String>();
    @Test
    public void searchClass() throws ClassNotFoundException 
        //包名
        String basePack = "com.baibin";
        //先把包名转换为路径,首先得到项目的classpath
        String classpath = Main.class.getResource("/").getPath();
        //然后把我们的包名basPach转换为路径名
        basePack = basePack.replace(".", File.separator);
        //然后把classpath和basePack合并
        String searchPath = classpath + basePack;
        doPath(new File(searchPath));
        //这个时候我们已经得到了指定包下所有的类的绝对路径了。我们现在利用这些绝对路径和java的反射机制得到他们的类对象
        for (String s : classPaths) 
            //把 D:\\work\\code\\20170401\\search-class\\target\\classes\\com\\baibin\\search\\a\\A.class 这样的绝对路径转换为全类名com.baibin.search.a.A
            s = s.replace(classpath.replace("/","\\\\").replaceFirst("\\\\\\\\",""),"").replace("\\\\",".").replace(".class","");
            Class cls = Class.forName(s);
            System.out.println(cls);
        
    
    /**
     * 该方法会得到所有的类,将类的绝对路径写入到classPaths中
     * @param file
     */
    private void doPath(File file) 
        if (file.isDirectory()) //文件夹
            //文件夹我们就递归
            File[] files = file.listFiles();
            for (File f1 : files) 
                doPath(f1);
            
         else //标准文件
            //标准文件我们就判断是否是class文件
            if (file.getName().endsWith(".class")) 
                //如果是class文件我们就放入我们的集合中。
                classPaths.add(file.getPath());
            
        
    

效果如下:

总结:这样的src下面的都比较容易处理,也很容易想到,但是jar包下面的就没这么简单了,

但是还是有办法的。

jar中的类如何获取:

jar下的类我们可以通过JarURLConnection类来或者,代码如下:

import org.junit.Test;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class JarMain 
    @Test
    public void searchClass() throws IOException, ClassNotFoundException 
        String basePack = "org.junit";
        //通过当前线程得到类加载器从而得到URL的枚举
        Enumeration<URL> urlEnumeration = Thread.currentThread().getContextClassLoader().getResources(basePack.replace(".", "/"));
        while (urlEnumeration.hasMoreElements()) 
            URL url = urlEnumeration.nextElement();//得到的结果大概是:jar:file:/C:/Users/ibm/.m2/repository/junit/junit/4.12/junit-4.12.jar!/org/junit
            String protocol = url.getProtocol();//大概是jar
            if ("jar".equalsIgnoreCase(protocol)) 
                //转换为JarURLConnection
                JarURLConnection connection = (JarURLConnection) url.openConnection();
                if (connection != null) 
                    JarFile jarFile = connection.getJarFile();
                    if (jarFile != null) 
                        //得到该jar文件下面的类实体
                        Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
                        while (jarEntryEnumeration.hasMoreElements()) 
                            /*entry的结果大概是这样:
                                    org/
                                    org/junit/
                                    org/junit/rules/
                                    org/junit/runners/*/
                            JarEntry entry = jarEntryEnumeration.nextElement();
                            String jarEntryName = entry.getName();
                            //这里我们需要过滤不是class文件和不在basePack包名下的类
                            if (jarEntryName.contains(".class") && jarEntryName.replaceAll("/",".").startsWith(basePack)) 
                                String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replace("/", ".");
                                Class cls = Class.forName(className);
                                System.out.println(cls);
                            
                        
                    
                
            
        
    

通过这两种方式我们就可以得到指定包名下面所有的类了,这个还是挺有用的,

比如spring中经常用来扫描指定包注解的实现等。

补充:获取指定包名下的所有类

写了一个工具类,用于获取指定包名下的所有类,支持递归遍历,支持注解过滤,可从 classpath (class 文件与 jar 包)中获取。

import java.io.File;
import java.io.FileFilter;
import java.lang.annotation.Annotation;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class ClassUtil 
    // 获取指定包名下的所有类
    public static List<Class<?>> getClassList(String packageName, boolean isRecursive) 
        List<Class<?>> classList = new ArrayList<Class<?>>();
        try 
            Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packageName.replaceAll("\\\\.", "/"));
            while (urls.hasMoreElements()) 
                URL url = urls.nextElement();
                if (url != null) 
                    String protocol = url.getProtocol();
                    if (protocol.equals("file")) 
                        String packagePath = url.getPath();
                        addClass(classList, packagePath, packageName, isRecursive);
                     else if (protocol.equals("jar")) 
                        JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
                        JarFile jarFile = jarURLConnection.getJarFile();
                        Enumeration<JarEntry> jarEntries = jarFile.entries();
                        while (jarEntries.hasMoreElements()) 
                            JarEntry jarEntry = jarEntries.nextElement();
                            String jarEntryName = jarEntry.getName();
                            if (jarEntryName.endsWith(".class")) 
                                String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
                                if (isRecursive || className.substring(0, className.lastIndexOf(".")).equals(packageName)) 
                                    classList.add(Class.forName(className));
                                
                            
                        
                    
                
            
         catch (Exception e) 
            e.printStackTrace();
        
        return classList;
    
    // 获取指定包名下的所有类(可根据注解进行过滤)
    public static List<Class<?>> getClassListByAnnotation(String packageName, Class<? extends Annotation> annotationClass) 
        List<Class<?>> classList = new ArrayList<Class<?>>();
        try 
            Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packageName.replaceAll("\\\\.", "/"));
            while (urls.hasMoreElements()) 
                URL url = urls.nextElement();
                if (url != null) 
                    String protocol = url.getProtocol();
                    if (protocol.equals("file")) 
                        String packagePath = url.getPath();
                        addClassByAnnotation(classList, packagePath, packageName, annotationClass);
                     else if (protocol.equals("jar")) 
                        JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
                        JarFile jarFile = jarURLConnection.getJarFile();
                        Enumeration<JarEntry> jarEntries = jarFile.entries();
                        while (jarEntries.hasMoreElements()) 
                            JarEntry jarEntry = jarEntries.nextElement();
                            String jarEntryName = jarEntry.getName();
                            if (jarEntryName.endsWith(".class")) 
                                String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
                                Class<?> cls = Class.forName(className);
                                if (cls.isAnnotationPresent(annotationClass)) 
                                    classList.add(cls);
                                
                            
                        
                    
                
            
         catch (Exception e) 
            e.printStackTrace();
        
        return classList;
    
    private static void addClass(List<Class<?>> classList, String packagePath, String packageName, boolean isRecursive) 
        try 
            File[] files = getClassFiles(packagePath);
            if (files != null) 
                for (File file : files) 
                    String fileName = file.getName();
                    if (file.isFile()) 
                        String className = getClassName(packageName, fileName);
                        classList.add(Class.forName(className));
                     else 
                        if (isRecursive) 
                            String subPackagePath = getSubPackagePath(packagePath, fileName);
                            String subPackageName = getSubPackageName(packageName, fileName);
                            addClass(classList, subPackagePath, subPackageName, isRecursive);
                        
                    
                
            
         catch (Exception e) 
            e.printStackTrace();
        
    
    private static File[] getClassFiles(String packagePath) 
        return new File(packagePath).listFiles(new FileFilter() 
            @Override
            public boolean accept(File file) 
                return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
            
        );
    
    private static String getClassName(String packageName, String fileName) 
        String className = fileName.substring(0, fileName.lastIndexOf("."));
        if (StringUtil.isNotEmpty(packageName)) 
            className = packageName + "." + className;
        
        return className;
    
    private static String getSubPackagePath(String packagePath, String filePath) 
        String subPackagePath = filePath;
        if (StringUtil.isNotEmpty(packagePath)) 
            subPackagePath = packagePath + "/" + subPackagePath;
        
        return subPackagePath;
    
    private static String getSubPackageName(String packageName, String filePath) 
        String subPackageName = filePath;
        if (StringUtil.isNotEmpty(packageName)) 
            subPackageName = packageName + "." + subPackageName;
        
        return subPackageName;
    
    private static void addClassByAnnotation(List<Class<?>> classList, String packagePath, String packageName, Class<? extends Annotation> annotationClass) 
        try 
            File[] files = getClassFiles(packagePath);
            if (files != null) 
                for (File file : files) 
                    String fileName = file.getName();
                    if (file.isFile()) 
                        String className = getClassName(packageName, fileName);
                        Class<?> cls = Class.forName(className);
                        if (cls.isAnnotationPresent(annotationClass)) 
                            classList.add(cls);
                        
                     else 
                        String subPackagePath = getSubPackagePath(packagePath, fileName);
                        String subPackageName = getSubPackageName(packageName, fileName);
                        addClassByAnnotation(classList, subPackagePath, subPackageName, annotationClass);
                    
                
            
         catch (Exception e) 
            e.printStackTrace();
        
    

以上就是使用java怎么扫描指定包下的类

以上是关于使用java怎么扫描指定包下的类的主要内容,如果未能解决你的问题,请参考以下文章

java读取指定package下的所有class

[Java]_[初级]_[Observer和Observable失效后如何使用java.beans包下的类来实现观察者模式]

使用注解开发,基于java类进行配置

java扫描某个包下的所有java类并加载

import的使用

java包中都放的都是.class文件吗?相同包下的类是指编译生成的.class文件都在同一个包里面吧