- 浏览: 65009 次
- 性别:
- 来自: 杭州
最新评论
-
meimei_123abc:
你好,可以把这个完整的代码给我发一个学习下吗,刚开始接触这一块 ...
在JNI中调用本地带结构体参数的函数 -
yangdong:
sorry,之后一直没再碰过 JNI,没法再写了。
在JNI中调用本地带结构体参数的函数 -
ihopethatwell:
楼主,能写一个传递数组的结构体?
在JNI中调用本地带结构体参数的函数 -
yangdong:
谢谢。我只是追求形似,所以找不到对应的写法。
Stream in Clojure -
jamesqiu:
Clojure的lazy-cat和Scala的Stream实现 ...
Stream in Clojure
Java 类路径扫描
- 博客分类:
- Java
Java 中缺乏内建的类路径扫描机制。但是这个机制对于做框架的人来说很常用。下面的工具类从类路径下面的文件或者 JAR 路径中扫描包,可以实现我们需要的功能。实现是基于 Spring 3.1.11.RELEASE 版的 PathMatchingResourcePatternResolver 修改的。去掉了原版中 ANT * 号匹配的功能。依赖 Google Guava, Apache Commons Collections 4, Apache Commons Lang。
这个实现的大概思路是
1. 先根据包名构建一个路径("." 换成 "/")
2. 用类加载器去加载这个路径对应的资源,得到一个 URL
3. 如果 URL 对应的是 JAR,扫描 JAR(非递归扫描)
4. 如果 URL 是文件系统,扫描文件系统(递归扫描)
3. 4., 一个递归一个非递归,主要原因是 JAR 对应的 API 返回的文件列表是展开的,所以我们不需要递归展开了。
比如有意思的是 2. 这一步。如果路径是空字符串 "",那么
1. 在 maven 下或者 IDE 下直接运行。得到的 URL 在文件系统下是 classes、test-classes 这些
2. 用 java -jar xxx.jar 运行。得到的 URL 是空的。但如果不传空字符串,传 com.xxx.app 就可以加载到资源
所以这个工具类的使用需要注意一点。如果你想让这个工具类在打成 JAR 包之后还能正常用,那么参数 basePackages 这里至少添上一个 com.xxx.app 之类的东西。
这个实现的大概思路是
1. 先根据包名构建一个路径("." 换成 "/")
2. 用类加载器去加载这个路径对应的资源,得到一个 URL
3. 如果 URL 对应的是 JAR,扫描 JAR(非递归扫描)
4. 如果 URL 是文件系统,扫描文件系统(递归扫描)
3. 4., 一个递归一个非递归,主要原因是 JAR 对应的 API 返回的文件列表是展开的,所以我们不需要递归展开了。
比如有意思的是 2. 这一步。如果路径是空字符串 "",那么
1. 在 maven 下或者 IDE 下直接运行。得到的 URL 在文件系统下是 classes、test-classes 这些
2. 用 java -jar xxx.jar 运行。得到的 URL 是空的。但如果不传空字符串,传 com.xxx.app 就可以加载到资源
所以这个工具类的使用需要注意一点。如果你想让这个工具类在打成 JAR 包之后还能正常用,那么参数 basePackages 这里至少添上一个 com.xxx.app 之类的东西。
import com.google.common.collect.Lists; import com.google.common.collect.Sets; import org.apache.commons.collections4.EnumerationUtils; import org.apache.commons.lang.StringUtils; import java.io.File; import java.io.IOException; import java.net.*; import java.util.*; import java.util.jar.JarEntry; import java.util.jar.JarFile; /** * 反射工具。实现是基于 Spring 3.1.11.RELEASE 版的 PathMatchingResourcePatternResolver 修改的。 * * @author fanshen * @since 2015/7/7 */ public class ReflectionUtils { private ReflectionUtils() { } /** * URL protocol for an entry from a jar file: "jar" */ private static final String URL_PROTOCOL_JAR = "jar"; /** * URL protocol for an entry from a zip file: "zip" */ private static final String URL_PROTOCOL_ZIP = "zip"; /** * URL protocol for an entry from a WebSphere jar file: "wsjar" */ private static final String URL_PROTOCOL_WSJAR = "wsjar"; /** * URL protocol for an entry from a JBoss jar file: "vfszip" */ private static final String URL_PROTOCOL_VFSZIP = "vfszip"; /** * URL protocol for an entry from an OC4J jar file: "code-source" */ private static final String URL_PROTOCOL_CODE_SOURCE = "code-source"; /** * Separator between JAR URL and file path within the JAR */ private static final String JAR_URL_SEPARATOR = "!/"; /** * URL prefix for loading from the file system: "file:" */ private static final String FILE_URL_PREFIX = "file:"; /** * 文件夹隔离符。 */ private static final String FOLDER_SEPARATOR = "/"; /** * 递归地在类路径中以指定的类加载器获取 dirPath 指定的目录下面所有的资源。cl 可为空,为空时取系统类加载器。 * 返回值一定不为 null。 */ public static ClassPathResource[] getClassPathResources(String dirPath, ClassLoader cl) throws IOException { if (cl == null) { cl = Thread.currentThread().getContextClassLoader(); } URL[] roots = getRoots(dirPath, cl); Set<ClassPathResource> result = new LinkedHashSet<ClassPathResource>(16); for (URL root : roots) { if (isJarResource(root)) { result.addAll(doFindPathMatchingJarResources(root)); } else { result.addAll(doFindPathMatchingFileResources(root, dirPath)); } } return result.toArray(new ClassPathResource[result.size()]); } /** * 获取指定 basePackages 下面所有能用 classLoaders 加载的类。 * * @param basePackages 这些包下面的类会被扫描 * @param classLoaders 用来加载 basePackages 下面类的类加载器 * @return 能够扫描到的类 */ public static Class<?>[] getAllClassPathClasses(String[] basePackages, ClassLoader... classLoaders) throws IOException { if (classLoaders.length <= 0) { classLoaders = new ClassLoader[] {Thread.currentThread().getContextClassLoader()}; } List<Class<?>> classes = Lists.newArrayListWithCapacity(100); for (ClassLoader classLoader : classLoaders) { for (String basePackage : basePackages) { classes.addAll(Lists.newArrayList(ReflectionUtils.getClasses(basePackage, classLoader))); } } return classes.toArray(new Class[classes.size()]); } /** * 使用 cl 指定的类加载器递归加载 packageName 指定的包名下面的所有的类。不会返回 null。 * cl 为空时使用系统类加载器。返回值一定不为 null。返回值中不包含类路径中的内部类。 */ public static Class<?>[] getClasses(String packageName, ClassLoader cl) throws IOException { if (cl == null) { cl = Thread.currentThread().getContextClassLoader(); } ClassPathResource[] resources = getClassPathResources(StringUtils.replace(packageName, ".", "/"), cl); List<Class<?>> result = Lists.newArrayList(); for (ClassPathResource resource : resources) { String urlPath = resource.getUrl().getPath(); if (!urlPath.endsWith(".class") || urlPath.contains("$")) { continue; } Class<?> cls = resolveClass(cl, resource); if (cls != null) { result.add(cls); } } return result.toArray(new Class[result.size()]); } private static Class<?> resolveClass(ClassLoader cl, ClassPathResource resource) { String className = resolveClassName(resource); try { return cl.loadClass(className); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } private static String resolveClassName(ClassPathResource resource) { String path = resource.getClassPathPath(); String className = path.substring(0, path.length() - ".class".length()); className = StringUtils.replace(className, "/", "."); return className; } private static URL[] getRoots(String dirPath, ClassLoader cl) throws IOException { Enumeration<URL> resources = cl.getResources(dirPath); List<URL> resourceUrls = EnumerationUtils.toList(resources); return resourceUrls.toArray(new URL[resourceUrls.size()]); } private static Collection<ClassPathResource> doFindPathMatchingFileResources(URL rootUrl, String dirPath) throws IOException { String filePath = rootUrl.getFile(); File file = new File(filePath); File rootDir = file.getAbsoluteFile(); return doFindMatchingFileSystemResources(rootDir, dirPath); } private static Collection<ClassPathResource> doFindMatchingFileSystemResources(File rootDir, String dirPath) throws IOException { Set<File> allFiles = Sets.newLinkedHashSet(); retrieveAllFiles(rootDir, allFiles); String classPathRoot = parseClassPathRoot(rootDir, dirPath); Set<ClassPathResource> result = new LinkedHashSet<ClassPathResource>(allFiles.size()); for (File file : allFiles) { String absolutePath = file.getAbsolutePath(); URL url = new URL("file:///" + absolutePath); String classPathPath = absolutePath.substring(classPathRoot.length()); classPathPath = StringUtils.replace(classPathPath, "\\", "/"); result.add(new ClassPathResource(url, classPathPath)); } return result; } private static String parseClassPathRoot(File rootDir, String dirPath) { String absolutePath = rootDir.getAbsolutePath(); absolutePath = StringUtils.replace(absolutePath, "\\", "/"); int lastIndex = absolutePath.lastIndexOf(dirPath); String result = absolutePath.substring(0, lastIndex); if (!result.endsWith("/")) { result = result + "/"; } return result; } private static void retrieveAllFiles(File dir, Set<File> allFiles) { File[] subFiles = dir.listFiles(); assert subFiles != null; allFiles.addAll(Arrays.asList(subFiles)); for (File subFile : subFiles) { if (subFile.isDirectory()) { retrieveAllFiles(subFile, allFiles); } } } private static Collection<ClassPathResource> doFindPathMatchingJarResources(URL rootUrl) throws IOException { URLConnection con = rootUrl.openConnection(); JarFile jarFile; String rootEntryPath; boolean newJarFile = false; if (con instanceof JarURLConnection) { // Should usually be the case for traditional JAR files. JarURLConnection jarCon = (JarURLConnection) con; jarCon.setUseCaches(true); jarFile = jarCon.getJarFile(); JarEntry jarEntry = jarCon.getJarEntry(); rootEntryPath = (jarEntry != null ? jarEntry.getName() : ""); } else { // No JarURLConnection -> need to resort to URL file parsing. // We'll assume URLs of the format "jar:path!/entry", with the protocol // being arbitrary as long as following the entry format. // We'll also handle paths with and without leading "file:" prefix. String urlFile = rootUrl.getFile(); int separatorIndex = urlFile.indexOf(JAR_URL_SEPARATOR); if (separatorIndex != -1) { String jarFileUrl = urlFile.substring(0, separatorIndex); rootEntryPath = urlFile.substring(separatorIndex + JAR_URL_SEPARATOR.length()); jarFile = getJarFile(jarFileUrl); } else { jarFile = new JarFile(urlFile); rootEntryPath = ""; } newJarFile = true; } try { if (!"".equals(rootEntryPath) && !rootEntryPath.endsWith("/")) { // Root entry path must end with slash to allow for proper matching. // The Sun JRE does not return a slash here, but BEA JRockit does. rootEntryPath = rootEntryPath + "/"; } Set<ClassPathResource> result = new LinkedHashSet<ClassPathResource>(8); for (Enumeration<JarEntry> entries = jarFile.entries(); entries.hasMoreElements();) { JarEntry entry = entries.nextElement(); String entryPath = entry.getName(); if (entryPath.startsWith(rootEntryPath)) { String relativePath = entryPath.substring(rootEntryPath.length()); String rootPath = rootUrl.getPath(); rootPath = rootPath.endsWith("/") ? rootPath : rootPath + "/"; String newPath = applyRelativePath(rootPath, relativePath); String classPathPath = applyRelativePath(rootEntryPath, relativePath); result.add(new ClassPathResource(new URL(newPath), classPathPath)); } } return result; } finally { // Close jar file, but only if freshly obtained - // not from JarURLConnection, which might cache the file reference. if (newJarFile) { jarFile.close(); } } } /** * Apply the given relative path to the given path, * assuming standard Java folder separation (i.e. "/" separators). * * @param path the path to start from (usually a full file path) * @param relativePath the relative path to apply * (relative to the full file path above) * @return the full file path that results from applying the relative path */ private static String applyRelativePath(String path, String relativePath) { int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR); if (separatorIndex != -1) { String newPath = path.substring(0, separatorIndex); if (!relativePath.startsWith(FOLDER_SEPARATOR)) { newPath += FOLDER_SEPARATOR; } return newPath + relativePath; } else { return relativePath; } } /** * Resolve the given jar file URL into a JarFile object. */ private static JarFile getJarFile(String jarFileUrl) throws IOException { if (jarFileUrl.startsWith(FILE_URL_PREFIX)) { try { return new JarFile(toURI(jarFileUrl).getSchemeSpecificPart()); } catch (URISyntaxException ex) { // Fallback for URLs that are not valid URIs (should hardly ever happen). return new JarFile(jarFileUrl.substring(FILE_URL_PREFIX.length())); } } else { return new JarFile(jarFileUrl); } } /** * Create a URI instance for the given location String, * replacing spaces with "%20" URI encoding first. * * @param location the location String to convert into a URI instance * @return the URI instance * @throws URISyntaxException if the location wasn't a valid URI */ private static URI toURI(String location) throws URISyntaxException { return new URI(StringUtils.replace(location, " ", "%20")); } private static boolean isJarResource(URL url) { String protocol = url.getProtocol(); return (URL_PROTOCOL_JAR.equals(protocol) || URL_PROTOCOL_ZIP.equals(protocol) || URL_PROTOCOL_VFSZIP.equals(protocol) || URL_PROTOCOL_WSJAR.equals(protocol) || (URL_PROTOCOL_CODE_SOURCE.equals(protocol) && url.getPath().contains(JAR_URL_SEPARATOR))); } /** * 类路径资源。 */ public static class ClassPathResource { /** * 此资源对应的 URL 对象。 */ private URL url; /** * 类路径下的路径。特点是这个路径字符串去掉了类路径的“根”部分。 */ private String classPathPath; /** * ctor. */ public ClassPathResource(URL url, String classPathPath) { this.url = url; this.classPathPath = classPathPath; } public URL getUrl() { return url; } public String getClassPathPath() { return classPathPath; } } }
发表评论
-
JParsec中如何在parser规则里引用lexer规则
2015-07-15 15:06 1528Java 的 Parser combinator 中最有名应该 ... -
Java 下面如何模拟友元
2011-02-16 02:13 5387Java 没有像 C++ 一样的友元。但是友元我认为是非常有用 ... -
精巧的状态机实现片段
2010-02-21 22:47 1146public enum SniperState { ... -
Inspiration from Clojure
2010-02-08 18:46 785http://www.infoq.com/presentati ... -
动态分类计数器
2010-01-10 00:30 1569昨天的工作遇到一个需求:要求根据用户 ID(Long 型)记录 ... -
Java 中文排序
2010-01-06 19:55 847在网上找到的最简单实用的方法: java.text.Coll ... -
多层类结构的对象相等性
2009-09-14 22:59 974在 Effective Java 中,Joshua Bloch ... -
Maven 中直接依赖怎样影响间接依赖
2009-07-05 21:03 3364相信学 Maven 的都看过 Maven 的官网文档的 Int ... -
FutureTask.isDone() 的返回问题
2009-05-30 06:41 6504FutureTask.isDone() 方法在 c ... -
获取文本控件的输出流
2009-04-22 23:08 1470在 Swing 中,文本控件没有输出流!所谓的文本控件这里指派 ... -
在JNI中调用本地带结构体参数的函数
2008-07-27 16:28 10234说起JNI,《The Java Native Interfac ...
相关推荐
ClassGraph - 超快速,超轻量级,并行化的Java类路径扫描程序,模块扫描程序和注释处理程序
classgraph,一个Uber快速、超轻量级Java类路径扫描器、模块扫描仪和注释处理器。.zip
ClassGraph是适用于Java,Scala,Kotlin和其他JVM语言的超快速并行化类路径扫描器和模块扫描器。 ClassGraph在Oracle Code One 2018上获得了Duke's Choice奖(该奖项是对Java生态系统中最有用和/或最具创新性的...
classgraph.zip,超级快速,超轻量级Java类路径扫描器。通过直接解析类文件二进制格式而不是使用反射扫描类路径。
通过java的反射技术获取,某个包路径下的类,并以表格形式打印类的属性注解及属性名称等,打印的结果以|分隔,复制到excel表格后,可以设置分列成需要的excel表格
##用法直接将jar文件添加到类路径中,Java doc也将与其关联。 (默认的jar文件不包含依赖项) ##示例扫描本地网络,查找具有以下选项的摄像头设备,包括摄像头缩略图和默认值,并返回所有发现的摄像头详细信息(IP...
Core在8至17-ea的Java版本上进行了测试,它是一个完全独立,高级,免费和开放源代码的Java框架构建库,它对于扫描类路径,在运行时生成类,促进使用反射,扫描非常有用。文件系统,执行字符串化的源代码等等。 ...
用JAVA开发的一个小型的目录监视系统,系统会每5秒自动扫描一次需要监视的目录,可以用来监视目录中文件大小及文件增减数目的变化。 Java日期选择控件完整源代码 14个目标文件 内容索引:JAVA源码,系统相关,日历,...
2.1 类路径 2.2 准备工作 2.3 实现类路径 2.3.1 Entry接口 2.3.2 DirEntry 2.3.3 ZipEntry 3 2.3.4 CompositeEntry 2.3.5 WildcardEntry 2.3.6 Classpath 2.4 测试本章代码 2.5 本章小结 第3章 解析...
用JAVA开发的一个小型的目录监视系统,系统会每5秒自动扫描一次需要监视的目录,可以用来监视目录中文件大小及文件增减数目的变化。 Java日期选择控件完整源代码 14个目标文件 内容索引:JAVA源码,系统相关,日历,...
用JAVA开发的一个小型的目录监视系统,系统会每5秒自动扫描一次需要监视的目录,可以用来监视目录中文件大小及文件增减数目的变化。 Java日期选择控件完整源代码 14个目标文件 内容索引:JAVA源码,系统相关,日历,...
Jadira 框架的 Java 类路径扫描器库 org.jadira.scanner/scanner/3.1.0.CR11/scanner-3.1.0.CR11.jar
用JAVA开发的一个小型的目录监视系统,系统会每5秒自动扫描一次需要监视的目录,可以用来监视目录中文件大小及文件增减数目的变化。 Java日期选择控件完整源代码 14个目标文件 内容索引:JAVA源码,系统相关,日历...
用JAVA开发的一个小型的目录监视系统,系统会每5秒自动扫描一次需要监视的目录,可以用来监视目录中文件大小及文件增减数目的变化。 Java日期选择控件完整源代码 14个目标文件 内容索引:JAVA源码,系统相关,日历...
类和资源的 Java 类路径扫描器 net.sf.corn/corn-cps/1.0.6/corn-cps-1.0.6.jar
类和资源的 Java 类路径扫描器 net.sf.corn/corn-cps/1.1.8/corn-cps-1.1.8.jar
类和资源的 Java 类路径扫描器 net.sf.corn/corn-cps/1.1.4/corn-cps-1.1.4.jar
类和资源的 Java 类路径扫描器 net.sf.corn/corn-cps/1.1.3/corn-cps-1.1.3.jar
类和资源的 Java 类路径扫描器 net.sf.corn/corn-cps/1.0.5/corn-cps-1.0.5.jar