通过Ant样式的PathMatcher在jar文件中找到与给定位置模式匹配的所有资源。
//package com.nowjava; import java.io.File; import java.io.IOException; /* from n o w j a v a . c o m - 时代Java*/ import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.JarURLConnection; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; import java.util.Enumeration; import java.util.LinkedHashSet; /* n o w j a v a . c o m 提供 */ import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; public class Main { /** URL prefix for loading from the file system: "file:" */ public static final String FILE_URL_PREFIX = "file:"; /** Separator between JAR URL and file path within the JAR */ public static final String JAR_URL_SEPARATOR = "!/"; /** * Find all resources in jar files that match the given location pattern * via the Ant-style PathMatcher. * * @param rootDirResource the root directory as Resource * @param subPattern the sub pattern to match (below the root directory) * @return the Set of matching Resource instances * @throws IOException in case of I/O errors * @see java.net.JarURLConnection * @see org.springframework.util.PathMatcher */ protected static <T extends Annotation> Set<Class<?>> doFindPathMatchingJarResources( URL sourceUrl, String basePackage, Class<T> searchedAnnotation) throws IOException { URLConnection con = sourceUrl.openConnection(); JarFile jarFile; String jarFileUrl; String rootEntryPath; boolean newJarFile = false; if (con instanceof JarURLConnection) { // Should usually be the case for traditional JAR files. JarURLConnection jarCon = (JarURLConnection) con; jarFile = jarCon.getJarFile(); jarFileUrl = jarCon.getJarFileURL().toExternalForm(); 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 = sourceUrl.getFile(); int separatorIndex = urlFile.indexOf(JAR_URL_SEPARATOR); if (separatorIndex != -1) { jarFileUrl = urlFile.substring(0, separatorIndex); rootEntryPath = urlFile.substring(separatorIndex + JAR_URL_SEPARATOR.length()); jarFile = getJarFile(jarFileUrl); } else { jarFile = new JarFile(urlFile); jarFileUrl = 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<Class<?>> result = new LinkedHashSet<Class<?>>(8); for (Enumeration<JarEntry> entries = jarFile.entries(); entries .hasMoreElements();) { JarEntry entry = entries.nextElement(); String entryPath = entry.getName(); if (entryPath.startsWith(rootEntryPath) && entryPath.endsWith(".class")) { int entryLength = entryPath.length(); String className = entryPath.replaceAll(File.separator, ".").substring(0, entryLength - 6); Class<?> foundClass = checkCandidate(className, searchedAnnotation); if (foundClass != null) result.add(foundClass); } } return result; } finally { // Close jar file, but only if freshly obtained - // not from JarURLConnection, which might cache the file reference. if (newJarFile) { jarFile.close(); } } } /** * Resolve the given jar file URL into a JarFile object. */ protected static JarFile getJarFile(String jarFileUrl) throws IOException { if (jarFileUrl.startsWith(FILE_URL_PREFIX)) { try { return new JarFile( new URI(jarFileUrl.replaceAll(" ", "%20")) .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); } } public static <T extends Annotation> Class<?> checkCandidate( String className, Class<T> searchedAnnotation) { try { Class<?> candidateClass = Class.forName(className); Target target = searchedAnnotation.getAnnotation(Target.class); for (ElementType elementType : target.value()) { switch (elementType) { case TYPE: if (candidateClass.getAnnotation(searchedAnnotation) != null) return candidateClass;