模拟spring项目扫描包实现

2019-01-07 10:58:30

突然想到spring是如何实现扫描包的,就想着自己手动来实现下,大佬勿喷

  1. package cn.trustway;
  2. import cn.trustway.exception.CdtBissException;
  3. import com.alibaba.fastjson.JSON;
  4. import org.slf4j.Logger;
  5. import org.slf4j.LoggerFactory;
  6. import java.io.File;
  7. import java.io.IOException;
  8. import java.net.URL;
  9. import java.nio.file.*;
  10. import java.nio.file.attribute.BasicFileAttributes;
  11. import java.util.ArrayList;
  12. import java.util.Enumeration;
  13. import java.util.List;
  14. import java.util.jar.JarEntry;
  15. import java.util.jar.JarFile;
  16. /**
  17. * @author wangjing
  18. * @version 1.0 created 2018/12/19
  19. */
  20. public class ScanClassOrJarTest {
  21. private static final Logger LOG = LoggerFactory.getLogger(ScanClassOrJarTest.class);
  22. public static void main(String[] args) {
  23. LOG.debug("classArray={}", JSON.toJSONString(getClasses("cn.trustway")));
  24. }
  25. public static List<Class<?>> getClasses(String packageName) {
  26. try {
  27. ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  28. String path = packageName.replace(".", File.separator);
  29. LOG.debug("path={}", path);
  30. Enumeration<URL> resources = classLoader.getResources(path);
  31. LOG.debug("资源路径={}", resources);
  32. List<Class<?>> classList = new ArrayList<>();
  33. while (resources.hasMoreElements()) {
  34. LOG.debug("resources.hasMoreElements()");
  35. URL resource = resources.nextElement();
  36. LOG.debug("resource.Protocol={}", resource.getProtocol());
  37. //getPath()在非jar包的classPath是不带(windows是file:/,linux是file:)的,
  38. //但在jar包里的资源路径带(windows是file:/,linux是file:)的
  39. LOG.debug("resource.path={}", resource.getPath());
  40. String protocol = resource.getProtocol();
  41. if ("jar".equals(protocol)) {
  42. String jarPath = resource.getPath().replace("file:", "");
  43. jarPath = jarPath.substring(0, jarPath.lastIndexOf("!"));
  44. classList.addAll(getClassFromJarFile(jarPath, path));
  45. } else if ("file".equals(protocol)) {
  46. String filePath = resource.getPath().replace("file:", "");
  47. classList.addAll(findClasses(filePath, packageName));
  48. }
  49. }
  50. return classList;
  51. } catch (Exception e) {
  52. LOG.error("扫描获取包内类异常:", e);
  53. throw new CdtBissException(e.getMessage());
  54. }
  55. }
  56. private static List<Class<?>> findClasses(String filePath, String packageName) {
  57. try {
  58. List<Class<?>> clazzs = new ArrayList<>();
  59. Path path = Paths.get(filePath);
  60. Files.walkFileTree(path, new FindJavaVisitor(clazzs, packageName, filePath));
  61. return clazzs;
  62. } catch (Exception e) {
  63. LOG.error("获取文件夹中class文件异常:", e);
  64. throw new CdtBissException(e.getMessage());
  65. }
  66. }
  67. /**
  68. * 获取jar包中的class文件
  69. *
  70. * @param jarPath
  71. * @param filePath
  72. * @return
  73. * @author wangjing
  74. * @date: 下午7:32 2018/12/19
  75. */
  76. private static List<Class<?>> getClassFromJarFile(String jarPath, String filePath) {
  77. try (JarFile jarFile = new JarFile(jarPath)) {
  78. List<Class<?>> clazzs = new ArrayList<>();
  79. List<JarEntry> jarEntryList = new ArrayList<>();
  80. Enumeration<JarEntry> entryEnumeration = jarFile.entries();
  81. while (entryEnumeration.hasMoreElements()) {
  82. JarEntry jarEntry = entryEnumeration.nextElement();
  83. //过滤出对应包下的class
  84. if (jarEntry.getName().startsWith(filePath)
  85. && jarEntry.getName().endsWith(".class")) {
  86. jarEntryList.add(jarEntry);
  87. }
  88. }
  89. for (JarEntry entry : jarEntryList) {
  90. String className = entry.getName().replace(File.separator, ".");
  91. className = className.substring(0, className.indexOf(".class"));
  92. clazzs.add(Thread.currentThread().getContextClassLoader().loadClass(className));
  93. }
  94. return clazzs;
  95. } catch (Exception e) {
  96. LOG.error("获取jar包class文件异常:", e);
  97. throw new CdtBissException(e.getMessage());
  98. }
  99. }
  100. private static class FindJavaVisitor extends SimpleFileVisitor<Path> {
  101. private List<Class<?>> classList;
  102. private String packageName;
  103. private String filePath;
  104. public FindJavaVisitor(List<Class<?>> classList, String packageName, String filePath) {
  105. this.classList = classList;
  106. this.packageName = packageName;
  107. this.filePath = filePath;
  108. }
  109. @Override
  110. public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
  111. //Path获取到的是所属文件夹或文件目录,不带/的
  112. if (file.toString().endsWith(".class") && !file.toString().contains("$")) {
  113. String className = file.toString()
  114. .replace(filePath, packageName)
  115. .replace("/", ".")
  116. .replace(".class", "");
  117. try {
  118. Class<?> clazz = Class.forName(className);
  119. classList.add(clazz);
  120. } catch (ClassNotFoundException e) {
  121. LOG.error("类加载异常:", e);
  122. throw new CdtBissException(e.getMessage());
  123. }
  124. }
  125. return FileVisitResult.CONTINUE;
  126. }
  127. }
  128. }

0
1
0

添加评论

正在回复:
取消
2
0
1
0