当前位置:   article > 正文

spring2.5开始的新特性:packagesToScan路径解析分析

springdoc.packagestoscan
1. <property name="packagesToScan" value=" com.xxx.entity" />, 会解析成"classpath*:com/xxx/ entity**/*.class",这个路径可以找出com/xxx/ entity根目录下的类文件

2. <property name="packagesToScan" value="com.xxx.entity .*" />, 会解析成"classpath*:com/xxx/ entity/***/*.class",这个路径可以找出com/xxx/entity根目录下一级子目录中的类文件,如com/xxx/entity/son/Hi.class , 而不能找出com/xxx/entity目录下的类文件。

3. <property name="packagesToScan" value="com.xxx.entity." />(注意最后的点) , 会转换成"classpath*:com/xxx/entity/**/*.class",这个路径可以找出com/xxx/entity根目录下及其子孙目录下所有的类文件. 一般来讲,这些就是我们要的文件。


上面是网友得出的结论,尚未有时间验证。

自己大致了解了一下.看了它的源码我们可以看到。

前缀默认为:"classpath*:"

后缀默认为:"/**/*.class"

PathMatchingResourcePatternResolver类中

if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {

把location去掉了前缀:"classpath*:"


关键是中间的解析

ClassUtil类中:

  1. public static String convertClassNameToResourcePath(String className) {
  2. Assert.notNull(className, "Class name must not be null");
  3. return className.replace('.', '/');
  4. }

我们可以看到它把.解析成了/

第一种则为:

com/tudou/entity/**/*.class

第二种则为:

com/tudou/entity/*/**/*.class

第三种则为:

com/tudou/entity//**/*.class

接下来就是判断了:

  1. package com.tudou.t2;
  2. /**
  3. * 测试spring源码内packageToScan的方法
  4. * @author tudou
  5. *
  6. */
  7. public class packageToScans {
  8. public static void main(String[] args) {
  9. String path1="classpath*:com/tudou/entity/**/*.class";
  10. String path2="classpath*:com/tudou/entity/*/**/*.class";
  11. String path3="classpath*:com/tudou/entity//**/*.class";
  12. String s1=determineRootDir(path1);
  13. String s2=determineRootDir(path2);
  14. String s3=determineRootDir(path3);
  15. //打印得成s1,s2,s3的值均为:classpath*:下面截取可以得到它的完整包名+类名
  16. String subPattern1 = path1.substring(s1.length());
  17. String subPattern2 = path1.substring(s2.length());
  18. String subPattern3 = path1.substring(s3.length());
  19. System.out.println(subPattern1);
  20. System.out.println(subPattern2);
  21. System.out.println(subPattern3);
  22. }
  23. protected static String determineRootDir(String location) {
  24. int prefixEnd = location.indexOf(":") + 1;
  25. int rootDirEnd = location.length();
  26. while (rootDirEnd > prefixEnd) {
  27. rootDirEnd = location.lastIndexOf('/', rootDirEnd - 2) + 1;
  28. }
  29. if (rootDirEnd == 0) {
  30. rootDirEnd = prefixEnd;
  31. }
  32. return location.substring(0, rootDirEnd);
  33. }
  34. }

再往后:

我们可以看到它会去jar,zip,路径里面去判断不同的路径。可谓是相当全面了!当然我们只管看路径寻找我们的类即可即可。

取绝对路径。



spring源码如下:

private static final String RESOURCE_PATTERN = "/**/*.class";
其中:String CLASSPATH_ALL_URL_PREFIX = "classpath*:";

protected void scanPackages(AnnotationConfiguration config) {if (this.packagesToScan != null) {try {for (String pkg : this.packagesToScan) {String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +ClassUtils.convertClassNameToResourcePath(pkg) + RESOURCE_PATTERN;Resource[] resources = this.resourcePatternResolver.getResources(pattern);MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);for (Resource resource : resources) {if (resource.isReadable()) {MetadataReader reader = readerFactory.getMetadataReader(resource);String className = reader.getClassMetadata().getClassName();if (matchesFilter(reader, readerFactory)) {config.addAnnotatedClass(this.resourcePatternResolver.getClassLoader().loadClass(className));}}}}}catch (IOException ex) {throw new MappingException("Failed to scan classpath for unlisted classes", ex);}catch (ClassNotFoundException ex) {throw new MappingException("Failed to load annotated classes from classpath", ex);}}}
 

  1. public static String convertClassNameToResourcePath(String className) {
  2. Assert.notNull(className, "Class name must not be null");
  3. return className.replace('.', '/');
  4. }

  1. ResourcePatternResolver类中主要代码:
  2. package org.springframework.core.io.support;
  3. import java.io.File;
  4. import java.io.IOException;
  5. import java.lang.reflect.InvocationHandler;
  6. import java.lang.reflect.Method;
  7. import java.net.JarURLConnection;
  8. import java.net.URISyntaxException;
  9. import java.net.URL;
  10. import java.net.URLConnection;
  11. import java.util.Collections;
  12. import java.util.Enumeration;
  13. import java.util.LinkedHashSet;
  14. import java.util.Set;
  15. import java.util.jar.JarEntry;
  16. import java.util.jar.JarFile;
  17. import org.apache.commons.logging.Log;
  18. import org.apache.commons.logging.LogFactory;
  19. import org.springframework.core.io.DefaultResourceLoader;
  20. import org.springframework.core.io.FileSystemResource;
  21. import org.springframework.core.io.Resource;
  22. import org.springframework.core.io.ResourceLoader;
  23. import org.springframework.core.io.UrlResource;
  24. import org.springframework.core.io.VfsResource;
  25. import org.springframework.util.AntPathMatcher;
  26. import org.springframework.util.Assert;
  27. import org.springframework.util.PathMatcher;
  28. import org.springframework.util.ReflectionUtils;
  29. import org.springframework.util.ResourceUtils;
  30. import org.springframework.util.StringUtils;
  31. public class PathMatchingResourcePatternResolver implements ResourcePatternResolver {
  32. private static final Log logger = LogFactory.getLog(PathMatchingResourcePatternResolver.class);
  33. private static Method equinoxResolveMethod;
  34. static {
  35. // Detect Equinox OSGi (e.g. on WebSphere 6.1)
  36. try {
  37. Class<?> fileLocatorClass = PathMatchingResourcePatternResolver.class.getClassLoader().loadClass(
  38. "org.eclipse.core.runtime.FileLocator");
  39. equinoxResolveMethod = fileLocatorClass.getMethod("resolve", URL.class);
  40. logger.debug("Found Equinox FileLocator for OSGi bundle URL resolution");
  41. }
  42. catch (Throwable ex) {
  43. equinoxResolveMethod = null;
  44. }
  45. }
  46. private final ResourceLoader resourceLoader;
  47. private PathMatcher pathMatcher = new AntPathMatcher();
  48. /**
  49. * Create a new PathMatchingResourcePatternResolver with a DefaultResourceLoader.
  50. * <p>ClassLoader access will happen via the thread context class loader.
  51. * @see org.springframework.core.io.DefaultResourceLoader
  52. */
  53. public PathMatchingResourcePatternResolver() {
  54. this.resourceLoader = new DefaultResourceLoader();
  55. }
  56. /**
  57. * Create a new PathMatchingResourcePatternResolver with a DefaultResourceLoader.
  58. * @param classLoader the ClassLoader to load classpath resources with,
  59. * or <code>null</code> for using the thread context class loader
  60. * at the time of actual resource access
  61. * @see org.springframework.core.io.DefaultResourceLoader
  62. */
  63. public PathMatchingResourcePatternResolver(ClassLoader classLoader) {
  64. this.resourceLoader = new DefaultResourceLoader(classLoader);
  65. }
  66. /**
  67. * Create a new PathMatchingResourcePatternResolver.
  68. * <p>ClassLoader access will happen via the thread context class loader.
  69. * @param resourceLoader the ResourceLoader to load root directories and
  70. * actual resources with
  71. */
  72. public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {
  73. Assert.notNull(resourceLoader, "ResourceLoader must not be null");
  74. this.resourceLoader = resourceLoader;
  75. }
  76. /**
  77. * Return the ResourceLoader that this pattern resolver works with.
  78. */
  79. public ResourceLoader getResourceLoader() {
  80. return this.resourceLoader;
  81. }
  82. /**
  83. * Return the ClassLoader that this pattern resolver works with
  84. * (never <code>null</code>).
  85. */
  86. public ClassLoader getClassLoader() {
  87. return getResourceLoader().getClassLoader();
  88. }
  89. /**
  90. * Set the PathMatcher implementation to use for this
  91. * resource pattern resolver. Default is AntPathMatcher.
  92. * @see org.springframework.util.AntPathMatcher
  93. */
  94. public void setPathMatcher(PathMatcher pathMatcher) {
  95. Assert.notNull(pathMatcher, "PathMatcher must not be null");
  96. this.pathMatcher = pathMatcher;
  97. }
  98. /**
  99. * Return the PathMatcher that this resource pattern resolver uses.
  100. */
  101. public PathMatcher getPathMatcher() {
  102. return this.pathMatcher;
  103. }
  104. public Resource getResource(String location) {
  105. return getResourceLoader().getResource(location);
  106. }
  107. public Resource[] getResources(String locationPattern) throws IOException {
  108. Assert.notNull(locationPattern, "Location pattern must not be null");
  109. if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
  110. // a class path resource (multiple resources for same name possible)
  111. if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
  112. // a class path resource pattern
  113. return findPathMatchingResources(locationPattern);
  114. }
  115. else {
  116. // all class path resources with the given name
  117. return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
  118. }
  119. }
  120. else {
  121. // Only look for a pattern after a prefix here
  122. // (to not get fooled by a pattern symbol in a strange prefix).
  123. int prefixEnd = locationPattern.indexOf(":") + 1;
  124. if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
  125. // a file pattern
  126. return findPathMatchingResources(locationPattern);
  127. }
  128. else {
  129. // a single resource with the given name
  130. return new Resource[] {getResourceLoader().getResource(locationPattern)};
  131. }
  132. }
  133. }
  134. /**
  135. * Find all class location resources with the given location via the ClassLoader.
  136. * @param location the absolute path within the classpath
  137. * @return the result as Resource array
  138. * @throws IOException in case of I/O errors
  139. * @see java.lang.ClassLoader#getResources
  140. * @see #convertClassLoaderURL
  141. */
  142. protected Resource[] findAllClassPathResources(String location) throws IOException {
  143. String path = location;
  144. if (path.startsWith("/")) {
  145. path = path.substring(1);
  146. }
  147. Enumeration<URL> resourceUrls = getClassLoader().getResources(path);
  148. Set<Resource> result = new LinkedHashSet<Resource>(16);
  149. while (resourceUrls.hasMoreElements()) {
  150. URL url = resourceUrls.nextElement();
  151. result.add(convertClassLoaderURL(url));
  152. }
  153. return result.toArray(new Resource[result.size()]);
  154. }
  155. /**
  156. * Convert the given URL as returned from the ClassLoader into a Resource object.
  157. * <p>The default implementation simply creates a UrlResource instance.
  158. * @param url a URL as returned from the ClassLoader
  159. * @return the corresponding Resource object
  160. * @see java.lang.ClassLoader#getResources
  161. * @see org.springframework.core.io.Resource
  162. */
  163. protected Resource convertClassLoaderURL(URL url) {
  164. return new UrlResource(url);
  165. }
  166. /**
  167. * Find all resources that match the given location pattern via the
  168. * Ant-style PathMatcher. Supports resources in jar files and zip files
  169. * and in the file system.
  170. * @param locationPattern the location pattern to match
  171. * @return the result as Resource array
  172. * @throws IOException in case of I/O errors
  173. * @see #doFindPathMatchingJarResources
  174. * @see #doFindPathMatchingFileResources
  175. * @see org.springframework.util.PathMatcher
  176. */
  177. protected Resource[] findPathMatchingResources(String locationPattern) throws IOException {
  178. String rootDirPath = determineRootDir(locationPattern);
  179. String subPattern = locationPattern.substring(rootDirPath.length());
  180. Resource[] rootDirResources = getResources(rootDirPath);
  181. Set<Resource> result = new LinkedHashSet<Resource>(16);
  182. for (Resource rootDirResource : rootDirResources) {
  183. rootDirResource = resolveRootDirResource(rootDirResource);
  184. if (isJarResource(rootDirResource)) {
  185. result.addAll(doFindPathMatchingJarResources(rootDirResource, subPattern));
  186. }
  187. else if (rootDirResource.getURL().getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
  188. result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirResource, subPattern, getPathMatcher()));
  189. }
  190. else {
  191. result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));
  192. }
  193. }
  194. if (logger.isDebugEnabled()) {
  195. logger.debug("Resolved location pattern [" + locationPattern + "] to resources " + result);
  196. }
  197. return result.toArray(new Resource[result.size()]);
  198. }
  199. /**
  200. * Determine the root directory for the given location.
  201. * <p>Used for determining the starting point for file matching,
  202. * resolving the root directory location to a <code>java.io.File</code>
  203. * and passing it into <code>retrieveMatchingFiles</code>, with the
  204. * remainder of the location as pattern.
  205. * <p>Will return "/WEB-INF/" for the pattern "/WEB-INF/*.xml",
  206. * for example.
  207. * @param location the location to check
  208. * @return the part of the location that denotes the root directory
  209. * @see #retrieveMatchingFiles
  210. */
  211. protected String determineRootDir(String location) {
  212. int prefixEnd = location.indexOf(":") + 1;
  213. int rootDirEnd = location.length();
  214. while (rootDirEnd > prefixEnd && getPathMatcher().isPattern(location.substring(prefixEnd, rootDirEnd))) {
  215. rootDirEnd = location.lastIndexOf('/', rootDirEnd - 2) + 1;
  216. }
  217. if (rootDirEnd == 0) {
  218. rootDirEnd = prefixEnd;
  219. }
  220. return location.substring(0, rootDirEnd);
  221. }
  222. /**
  223. * Resolve the specified resource for path matching.
  224. * <p>The default implementation detects an Equinox OSGi "bundleresource:"
  225. * / "bundleentry:" URL and resolves it into a standard jar file URL that
  226. * can be traversed using Spring's standard jar file traversal algorithm.
  227. * @param original the resource to resolve
  228. * @return the resolved resource (may be identical to the passed-in resource)
  229. * @throws IOException in case of resolution failure
  230. */
  231. protected Resource resolveRootDirResource(Resource original) throws IOException {
  232. if (equinoxResolveMethod != null) {
  233. URL url = original.getURL();
  234. if (url.getProtocol().startsWith("bundle")) {
  235. return new UrlResource((URL) ReflectionUtils.invokeMethod(equinoxResolveMethod, null, url));
  236. }
  237. }
  238. return original;
  239. }
  240. /**
  241. * Return whether the given resource handle indicates a jar resource
  242. * that the <code>doFindPathMatchingJarResources</code> method can handle.
  243. * <p>The default implementation checks against the URL protocols
  244. * "jar", "zip" and "wsjar" (the latter are used by BEA WebLogic Server
  245. * and IBM WebSphere, respectively, but can be treated like jar files).
  246. * @param resource the resource handle to check
  247. * (usually the root directory to start path matching from)
  248. * @see #doFindPathMatchingJarResources
  249. * @see org.springframework.util.ResourceUtils#isJarURL
  250. */
  251. protected boolean isJarResource(Resource resource) throws IOException {
  252. return ResourceUtils.isJarURL(resource.getURL());
  253. }
  254. /**
  255. * Find all resources in jar files that match the given location pattern
  256. * via the Ant-style PathMatcher.
  257. * @param rootDirResource the root directory as Resource
  258. * @param subPattern the sub pattern to match (below the root directory)
  259. * @return the Set of matching Resource instances
  260. * @throws IOException in case of I/O errors
  261. * @see java.net.JarURLConnection
  262. * @see org.springframework.util.PathMatcher
  263. */
  264. protected Set<Resource> doFindPathMatchingJarResources(Resource rootDirResource, String subPattern)
  265. throws IOException {
  266. URLConnection con = rootDirResource.getURL().openConnection();
  267. JarFile jarFile;
  268. String jarFileUrl;
  269. String rootEntryPath;
  270. boolean newJarFile = false;
  271. if (con instanceof JarURLConnection) {
  272. // Should usually be the case for traditional JAR files.
  273. JarURLConnection jarCon = (JarURLConnection) con;
  274. jarCon.setUseCaches(false);
  275. jarFile = jarCon.getJarFile();
  276. jarFileUrl = jarCon.getJarFileURL().toExternalForm();
  277. JarEntry jarEntry = jarCon.getJarEntry();
  278. rootEntryPath = (jarEntry != null ? jarEntry.getName() : "");
  279. }
  280. else {
  281. // No JarURLConnection -> need to resort to URL file parsing.
  282. // We'll assume URLs of the format "jar:path!/entry", with the protocol
  283. // being arbitrary as long as following the entry format.
  284. // We'll also handle paths with and without leading "file:" prefix.
  285. String urlFile = rootDirResource.getURL().getFile();
  286. int separatorIndex = urlFile.indexOf(ResourceUtils.JAR_URL_SEPARATOR);
  287. if (separatorIndex != -1) {
  288. jarFileUrl = urlFile.substring(0, separatorIndex);
  289. rootEntryPath = urlFile.substring(separatorIndex + ResourceUtils.JAR_URL_SEPARATOR.length());
  290. jarFile = getJarFile(jarFileUrl);
  291. }
  292. else {
  293. jarFile = new JarFile(urlFile);
  294. jarFileUrl = urlFile;
  295. rootEntryPath = "";
  296. }
  297. newJarFile = true;
  298. }
  299. try {
  300. if (logger.isDebugEnabled()) {
  301. logger.debug("Looking for matching resources in jar file [" + jarFileUrl + "]");
  302. }
  303. if (!"".equals(rootEntryPath) && !rootEntryPath.endsWith("/")) {
  304. // Root entry path must end with slash to allow for proper matching.
  305. // The Sun JRE does not return a slash here, but BEA JRockit does.
  306. rootEntryPath = rootEntryPath + "/";
  307. }
  308. Set<Resource> result = new LinkedHashSet<Resource>(8);
  309. for (Enumeration<JarEntry> entries = jarFile.entries(); entries.hasMoreElements();) {
  310. JarEntry entry = entries.nextElement();
  311. String entryPath = entry.getName();
  312. if (entryPath.startsWith(rootEntryPath)) {
  313. String relativePath = entryPath.substring(rootEntryPath.length());
  314. if (getPathMatcher().match(subPattern, relativePath)) {
  315. result.add(rootDirResource.createRelative(relativePath));
  316. }
  317. }
  318. }
  319. return result;
  320. }
  321. finally {
  322. // Close jar file, but only if freshly obtained -
  323. // not from JarURLConnection, which might cache the file reference.
  324. if (newJarFile) {
  325. jarFile.close();
  326. }
  327. }
  328. }
  329. /**
  330. * Resolve the given jar file URL into a JarFile object.
  331. */
  332. protected JarFile getJarFile(String jarFileUrl) throws IOException {
  333. if (jarFileUrl.startsWith(ResourceUtils.FILE_URL_PREFIX)) {
  334. try {
  335. return new JarFile(ResourceUtils.toURI(jarFileUrl).getSchemeSpecificPart());
  336. }
  337. catch (URISyntaxException ex) {
  338. // Fallback for URLs that are not valid URIs (should hardly ever happen).
  339. return new JarFile(jarFileUrl.substring(ResourceUtils.FILE_URL_PREFIX.length()));
  340. }
  341. }
  342. else {
  343. return new JarFile(jarFileUrl);
  344. }
  345. }
  346. /**
  347. * Find all resources in the file system that match the given location pattern
  348. * via the Ant-style PathMatcher.
  349. * @param rootDirResource the root directory as Resource
  350. * @param subPattern the sub pattern to match (below the root directory)
  351. * @return the Set of matching Resource instances
  352. * @throws IOException in case of I/O errors
  353. * @see #retrieveMatchingFiles
  354. * @see org.springframework.util.PathMatcher
  355. */
  356. protected Set<Resource> doFindPathMatchingFileResources(Resource rootDirResource, String subPattern)
  357. throws IOException {
  358. File rootDir;
  359. try {
  360. rootDir = rootDirResource.getFile().getAbsoluteFile();
  361. }
  362. catch (IOException ex) {
  363. if (logger.isWarnEnabled()) {
  364. logger.warn("Cannot search for matching files underneath " + rootDirResource +
  365. " because it does not correspond to a directory in the file system", ex);
  366. }
  367. return Collections.emptySet();
  368. }
  369. return doFindMatchingFileSystemResources(rootDir, subPattern);
  370. }
  371. /**
  372. * Find all resources in the file system that match the given location pattern
  373. * via the Ant-style PathMatcher.
  374. * @param rootDir the root directory in the file system
  375. * @param subPattern the sub pattern to match (below the root directory)
  376. * @return the Set of matching Resource instances
  377. * @throws IOException in case of I/O errors
  378. * @see #retrieveMatchingFiles
  379. * @see org.springframework.util.PathMatcher
  380. */
  381. protected Set<Resource> doFindMatchingFileSystemResources(File rootDir, String subPattern) throws IOException {
  382. if (logger.isDebugEnabled()) {
  383. logger.debug("Looking for matching resources in directory tree [" + rootDir.getPath() + "]");
  384. }
  385. Set<File> matchingFiles = retrieveMatchingFiles(rootDir, subPattern);
  386. Set<Resource> result = new LinkedHashSet<Resource>(matchingFiles.size());
  387. for (File file : matchingFiles) {
  388. result.add(new FileSystemResource(file));
  389. }
  390. return result;
  391. }
  392. /**
  393. * Retrieve files that match the given path pattern,
  394. * checking the given directory and its subdirectories.
  395. * @param rootDir the directory to start from
  396. * @param pattern the pattern to match against,
  397. * relative to the root directory
  398. * @return the Set of matching File instances
  399. * @throws IOException if directory contents could not be retrieved
  400. */
  401. protected Set<File> retrieveMatchingFiles(File rootDir, String pattern) throws IOException {
  402. if (!rootDir.exists()) {
  403. // Silently skip non-existing directories.
  404. if (logger.isDebugEnabled()) {
  405. logger.debug("Skipping [" + rootDir.getAbsolutePath() + "] because it does not exist");
  406. }
  407. return Collections.emptySet();
  408. }
  409. if (!rootDir.isDirectory()) {
  410. // Complain louder if it exists but is no directory.
  411. if (logger.isWarnEnabled()) {
  412. logger.warn("Skipping [" + rootDir.getAbsolutePath() + "] because it does not denote a directory");
  413. }
  414. return Collections.emptySet();
  415. }
  416. if (!rootDir.canRead()) {
  417. if (logger.isWarnEnabled()) {
  418. logger.warn("Cannot search for matching files underneath directory [" + rootDir.getAbsolutePath() +
  419. "] because the application is not allowed to read the directory");
  420. }
  421. return Collections.emptySet();
  422. }
  423. String fullPattern = StringUtils.replace(rootDir.getAbsolutePath(), File.separator, "/");
  424. if (!pattern.startsWith("/")) {
  425. fullPattern += "/";
  426. }
  427. fullPattern = fullPattern + StringUtils.replace(pattern, File.separator, "/");
  428. Set<File> result = new LinkedHashSet<File>(8);
  429. doRetrieveMatchingFiles(fullPattern, rootDir, result);
  430. return result;
  431. }
  432. /**
  433. * Recursively retrieve files that match the given pattern,
  434. * adding them to the given result list.
  435. * @param fullPattern the pattern to match against,
  436. * with prepended root directory path
  437. * @param dir the current directory
  438. * @param result the Set of matching File instances to add to
  439. * @throws IOException if directory contents could not be retrieved
  440. */
  441. protected void doRetrieveMatchingFiles(String fullPattern, File dir, Set<File> result) throws IOException {
  442. if (logger.isDebugEnabled()) {
  443. logger.debug("Searching directory [" + dir.getAbsolutePath() +
  444. "] for files matching pattern [" + fullPattern + "]");
  445. }
  446. File[] dirContents = dir.listFiles();
  447. if (dirContents == null) {
  448. if (logger.isWarnEnabled()) {
  449. logger.warn("Could not retrieve contents of directory [" + dir.getAbsolutePath() + "]");
  450. }
  451. return;
  452. }
  453. for (File content : dirContents) {
  454. String currPath = StringUtils.replace(content.getAbsolutePath(), File.separator, "/");
  455. if (content.isDirectory() && getPathMatcher().matchStart(fullPattern, currPath + "/")) {
  456. if (!content.canRead()) {
  457. if (logger.isDebugEnabled()) {
  458. logger.debug("Skipping subdirectory [" + dir.getAbsolutePath() +
  459. "] because the application is not allowed to read the directory");
  460. }
  461. }
  462. else {
  463. doRetrieveMatchingFiles(fullPattern, content, result);
  464. }
  465. }
  466. if (getPathMatcher().match(fullPattern, currPath)) {
  467. result.add(content);
  468. }
  469. }
  470. }
  471. /**
  472. * Inner delegate class, avoiding a hard JBoss VFS API dependency at runtime.
  473. */
  474. private static class VfsResourceMatchingDelegate {
  475. public static Set<Resource> findMatchingResources(
  476. Resource rootResource, String locationPattern, PathMatcher pathMatcher) throws IOException {
  477. Object root = VfsPatternUtils.findRoot(rootResource.getURL());
  478. PatternVirtualFileVisitor visitor =
  479. new PatternVirtualFileVisitor(VfsPatternUtils.getPath(root), locationPattern, pathMatcher);
  480. VfsPatternUtils.visit(root, visitor);
  481. return visitor.getResources();
  482. }
  483. }
  484. /**
  485. * VFS visitor for path matching purposes.
  486. */
  487. private static class PatternVirtualFileVisitor implements InvocationHandler {
  488. private final String subPattern;
  489. private final PathMatcher pathMatcher;
  490. private final String rootPath;
  491. private final Set<Resource> resources = new LinkedHashSet<Resource>();
  492. public PatternVirtualFileVisitor(String rootPath, String subPattern, PathMatcher pathMatcher) {
  493. this.subPattern = subPattern;
  494. this.pathMatcher = pathMatcher;
  495. this.rootPath = (rootPath.length() == 0 || rootPath.endsWith("/") ? rootPath : rootPath + "/");
  496. }
  497. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  498. String methodName = method.getName();
  499. if (Object.class.equals(method.getDeclaringClass())) {
  500. if (methodName.equals("equals")) {
  501. // Only consider equal when proxies are identical.
  502. return (proxy == args[0]);
  503. }
  504. else if (methodName.equals("hashCode")) {
  505. return System.identityHashCode(proxy);
  506. }
  507. }
  508. else if ("getAttributes".equals(methodName)) {
  509. return getAttributes();
  510. }
  511. else if ("visit".equals(methodName)) {
  512. visit(args[0]);
  513. return null;
  514. }
  515. else if ("toString".equals(methodName)) {
  516. return toString();
  517. }
  518. throw new IllegalStateException("Unexpected method invocation: " + method);
  519. }
  520. public void visit(Object vfsResource) {
  521. if (this.pathMatcher.match(this.subPattern,
  522. VfsPatternUtils.getPath(vfsResource).substring(this.rootPath.length()))) {
  523. this.resources.add(new VfsResource(vfsResource));
  524. }
  525. }
  526. public Object getAttributes() {
  527. return VfsPatternUtils.getVisitorAttribute();
  528. }
  529. public Set<Resource> getResources() {
  530. return this.resources;
  531. }
  532. @SuppressWarnings("unused")
  533. public int size() {
  534. return this.resources.size();
  535. }
  536. public String toString() {
  537. StringBuilder sb = new StringBuilder();
  538. sb.append("sub-pattern: ").append(this.subPattern);
  539. sb.append(", resources: ").append(this.resources);
  540. return sb.toString();
  541. }
  542. }
  543. }



CachingMetadataReaderFactory类核心代码:

  1. package org.springframework.core.type.classreading;
  2. import java.io.IOException;
  3. import java.util.LinkedHashMap;
  4. import java.util.Map;
  5. import org.springframework.core.io.Resource;
  6. import org.springframework.core.io.ResourceLoader;
  7. /**
  8. * Caching implementation of the {@link MetadataReaderFactory} interface,
  9. * caching {@link MetadataReader} per Spring {@link Resource} handle
  10. * (i.e. per ".class" file).
  11. *
  12. * @author Juergen Hoeller
  13. * @author Costin Leau
  14. * @since 2.5
  15. */
  16. public class CachingMetadataReaderFactory extends SimpleMetadataReaderFactory {
  17. /** Default maximum number of entries for the MetadataReader cache: 256 */
  18. public static final int DEFAULT_CACHE_LIMIT = 256;
  19. private volatile int cacheLimit = DEFAULT_CACHE_LIMIT;
  20. private final Map<Resource, MetadataReader> classReaderCache =
  21. new LinkedHashMap<Resource, MetadataReader>(DEFAULT_CACHE_LIMIT, 0.75f, true) {
  22. @Override
  23. protected boolean removeEldestEntry(Map.Entry<Resource, MetadataReader> eldest) {
  24. return size() > getCacheLimit();
  25. }
  26. };
  27. /**
  28. * Create a new CachingMetadataReaderFactory for the default class loader.
  29. */
  30. public CachingMetadataReaderFactory() {
  31. super();
  32. }
  33. /**
  34. * Create a new CachingMetadataReaderFactory for the given resource loader.
  35. * @param resourceLoader the Spring ResourceLoader to use
  36. * (also determines the ClassLoader to use)
  37. */
  38. public CachingMetadataReaderFactory(ResourceLoader resourceLoader) {
  39. super(resourceLoader);
  40. }
  41. /**
  42. * Create a new CachingMetadataReaderFactory for the given class loader.
  43. * @param classLoader the ClassLoader to use
  44. */
  45. public CachingMetadataReaderFactory(ClassLoader classLoader) {
  46. super(classLoader);
  47. }
  48. /**
  49. * Specify the maximum number of entries for the MetadataReader cache.
  50. * Default is 256.
  51. */
  52. public void setCacheLimit(int cacheLimit) {
  53. this.cacheLimit = cacheLimit;
  54. }
  55. /**
  56. * Return the maximum number of entries for the MetadataReader cache.
  57. */
  58. public int getCacheLimit() {
  59. return this.cacheLimit;
  60. }
  61. @Override
  62. public MetadataReader getMetadataReader(Resource resource) throws IOException {
  63. if (getCacheLimit() <= 0) {
  64. return super.getMetadataReader(resource);
  65. }
  66. synchronized (this.classReaderCache) {
  67. MetadataReader metadataReader = this.classReaderCache.get(resource);
  68. if (metadataReader == null) {
  69. metadataReader = super.getMetadataReader(resource);
  70. this.classReaderCache.put(resource, metadataReader);
  71. }
  72. return metadataReader;
  73. }
  74. }
  75. }





                
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/66395?site
推荐阅读
相关标签
  

闽ICP备14008679号