包扫描在框架中应用很广泛,在spring中,通过给自己的类加注解的方式,利用spring的包扫描,完成依赖注入。
1 package com.test.package_scanner.core;
2
3 import java.io.File;
4 import java.io.FileFilter;
5 import java.io.IOException;
6 import java.net.JarURLConnection;
7 import java.net.URISyntaxException;
8 import java.net.URL;
9 import java.util.Enumeration;
10 import java.util.jar.JarEntry;
11
12 public abstract class PackageScanner {
13
14 public PackageScanner() {
15 }
16
17 // scanPackage方法的重载
18 public void scanPackage(Class<?> klass) {
19 scanPackage(klass.getPackage().getName());
20 }
21
22 public void scanPackage(String packageName) {
23 // 将包名称转换为路径名称的形式
24 String packagePath = packageName.replace(".", "/");
25
26 try {
27 // 由类加载器得到URL的枚举
28 Enumeration<URL> resources = Thread.currentThread()
29 .getContextClassLoader()
30 .getResources(packagePath);
31
32 while (resources.hasMoreElements()) {
33 URL url = resources.nextElement();
34
35 // 处理jar包
36 if (url.getProtocol().equals("jar")) {
37 parse(url);
38 } else {
39 File file = new File(url.toURI());
40
41 if (file.exists()) {
42 // 处理普通包
43 parse(file, packageName);
44 }
45 }
46 }
47 } catch (IOException e) {
48 e.printStackTrace();
49 } catch (URISyntaxException e) {
50 e.printStackTrace();
51 }
52 }
53 // 抽象方法,由用户自行处理扫描到的类
54 public abstract void dealClass(Class<?> klass);
55
56 // jar包的扫描
57 private void parse(URL url) throws IOException {
58 Enumeration<JarEntry> jarEntries = ((JarURLConnection) url.openConnection())
59 .getJarFile().entries();
60
61 while (jarEntries.hasMoreElements()) {
62 JarEntry jarEntry = jarEntries.nextElement();
63 String jarName = jarEntry.getName();
64
65 if (!jarEntry.isDirectory() && jarName.endsWith(".class")) {
66 // 将文件路径名转换为包名称的形式
67 dealClassName(jarName.replace("/", ".").replace(".class", ""));
68 }
69 }
70 }
71
72 // 普通包的扫描
73 private void parse(File curFile, String packageName) {
74 File[] fileList = curFile.listFiles(new FileFilter() {
75 // 筛选文件夹和class文件,其余文件不处理
76 @Override
77 public boolean accept(File pathname) {
78 return pathname.isDirectory() || pathname.getName().endsWith(".class");
79 }
80 });
81
82 // 目录就是一颗树,对树进行递归,找到class文件
83 for (File file : fileList) {
84 String fileName = file.getName();
85 if (file.isDirectory()) {
86 parse(file, packageName + "." + fileName);
87 } else {
88 String className = packageName + "." + fileName.replace(".class", "");
89 dealClassName(className);
90 }
91 }
92 }
93
94 // 将找到的class文件生成类对象
95 private void dealClassName(String className) {
96 try {
97 Class<?> klass = Class.forName(className);
98
99 // 注解、接口、枚举、原始类型不做处理
100 if (!klass.isAnnotation()
101 && !klass.isInterface()
102 && !klass.isEnum()
103 && !klass.isPrimitive()) {
104 dealClass(klass);
105 }
106 } catch (ClassNotFoundException e) {
107 e.printStackTrace();
108 }
109 }
110
111 }
对如下目录扫描
1 package com.test.package_scanner.demo;
2
3 import com.test.package_scanner.core.PackageScanner;
4
5 public class Demo {
6
7 public static void main(String[] args) {
8 new PackageScanner() {
9
10 @Override
11 public void dealClass(Class<?> klass) {
12 System.out.println(klass);
13 }
14 }.scanPackage("com");
15 }
16
17 }
结果如下