java 如何扫描指定包下类(包括jar中的java类)
在很多的实际场景中,我们需要得到某个包名下面所有的类,
包括我们自己在src里写的java类和一些第三方提供的jar包里的类,那么怎么来实现呢?
今天带大家来完成这件事。
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';//先把包名转换为路径,首先得到项目的classpathString 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:workcode20170401search-classtargetclassescombaibinsearchaA.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)) {//转换为JarURLConnectionJarURLConnection 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();} }}
以上为个人经验,希望能给大家一个参考,也希望大家多多支持好吧啦网。如有错误或未考虑完全的地方,望不吝赐教。
相关文章:
