3
3
import java .io .File ;
4
4
import java .io .FileFilter ;
5
5
import java .io .IOException ;
6
+ import java .io .UnsupportedEncodingException ;
6
7
import java .net .JarURLConnection ;
7
8
import java .net .URL ;
8
9
import java .net .URLDecoder ;
10
+ import java .nio .charset .Charset ;
9
11
import java .util .Enumeration ;
10
12
import java .util .LinkedHashSet ;
11
13
import java .util .Set ;
15
17
import java .util .logging .Logger ;
16
18
17
19
/**
18
- * 扫描包,将其中的类提取到Set<Class<?>>容器中
20
+ * 扫描包,获取包下的所有类
21
+ *
22
+ * @author HeLei
19
23
*/
20
24
public final class PackageScanner {
25
+ private static final Logger logger = Logger .getLogger (PackageScanner .class .getName ());
26
+
21
27
private PackageScanner () {
22
28
}
23
29
24
- private final static Logger logger = Logger .getLogger (PackageScanner .class .getName ());
25
-
26
- public static Set <Class <?>> getClasses (String pack ) {
30
+ /**
31
+ * 查找包名下的所有类实例
32
+ *
33
+ * @param packageName 包名
34
+ * @return 类实例集合
35
+ */
36
+ public static Set <Class <?>> getClasses (String packageName ) {
27
37
// 第一个class类的集合
28
38
Set <Class <?>> classes = new LinkedHashSet <Class <?>>();
29
- // 是否循环迭代
30
- boolean recursive = true ;
31
39
// 获取包的名字并进行替换
32
- String packageName = pack ;
33
40
String packageDirName = packageName .replace ('.' , '/' );
34
- // 定义一个枚举的集合 并进行循环来处理这个目录下的things
41
+ // logger.debug(new ClassPathResource(packageDirName).getURI());
42
+ // 定义一个枚举的集合 并进行循环来处理这个目录下的内容
35
43
Enumeration <URL > dirs ;
36
44
try {
37
45
dirs = Thread .currentThread ().getContextClassLoader ().getResources (packageDirName );
38
- // 循环迭代下去
39
- while (dirs .hasMoreElements ()) {
40
- // 获取下一个元素
41
- URL url = dirs .nextElement ();
42
- // 得到协议的名称
43
- String protocol = url .getProtocol ();
44
- // 如果是以文件的形式保存在服务器上
45
- if ("file" .equals (protocol )) {
46
- logger .fine ("file类型的扫描" );
47
- // 获取包的物理路径
48
- String filePath = URLDecoder .decode (url .getFile (), "UTF-8" );
49
- // 以文件的方式扫描整个包下的文件 并添加到集合中
50
- findAndAddClassesInPackageByFile (packageName , filePath , recursive , classes );
51
- } else if ("jar" .equals (protocol )) {
52
- // 如果是jar包文件
53
- // 定义一个JarFile
54
- logger .fine ("jar类型的扫描" );
55
- JarFile jar ;
56
- try {
57
- // 获取jar
58
- jar = ((JarURLConnection ) url .openConnection ()).getJarFile ();
59
- // 从此jar包 得到一个枚举类
60
- Enumeration <JarEntry > entries = jar .entries ();
61
- // 同样的进行循环迭代
62
- while (entries .hasMoreElements ()) {
63
- // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
64
- JarEntry entry = entries .nextElement ();
65
- String name = entry .getName ();
66
- // 如果是以/开头的
67
- if (name .charAt (0 ) == '/' ) {
68
- // 获取后面的字符串
69
- name = name .substring (1 );
70
- }
71
- // 如果前半部分和定义的包名相同
72
- if (name .startsWith (packageDirName )) {
73
- int idx = name .lastIndexOf ('/' );
74
- // 如果以"/"结尾 是一个包
75
- if (idx != -1 ) {
76
- // 获取包名 把"/"替换成"."
77
- packageName = name .substring (0 , idx ).replace ('/' , '.' );
78
- }
79
- // 如果可以迭代下去 并且是一个包
80
- if ((idx != -1 ) || recursive ) {
81
- // 如果是一个.class文件 而且不是目录
82
- if (name .endsWith (".class" ) && !entry .isDirectory ()) {
83
- // 去掉后面的".class" 获取真正的类名
84
- String className = name .substring (packageName .length () + 1 , name .length () - 6 );
85
- try {
86
- // 添加到classes
87
- classes .add (Class .forName (packageName + '.' + className ));
88
- } catch (ClassNotFoundException e ) {
89
- e .printStackTrace ();
90
- logger .log (Level .SEVERE , "添加用户自定义视图类错误找不到此类的.class文件" , e );
91
- }
92
- }
93
- }
94
- }
95
- }
96
- } catch (IOException e ) {
97
- e .printStackTrace ();
98
- logger .log (Level .SEVERE , "在扫描用户定义视图时从jar包获取文件出错" , e );
99
- }
46
+ } catch (IOException e ) {
47
+ logger .log (Level .WARNING , packageName + " read failed!" , e );
48
+ throw new IllegalArgumentException (e );
49
+ }
50
+ // 循环迭代下去
51
+ while (dirs .hasMoreElements ()) {
52
+ // 获取下一个元素
53
+ URL url = dirs .nextElement ();
54
+ // 得到协议的名称
55
+ String protocol = url .getProtocol ();
56
+ // 如果是以文件的形式保存在服务器上
57
+ if ("file" .equals (protocol )) {
58
+ logger .fine ("scan file system" );
59
+ // 获取包的物理路径
60
+ String filePath ;
61
+ try {
62
+ filePath = URLDecoder .decode (url .getFile (), Charset .defaultCharset ().name ());
63
+ } catch (UnsupportedEncodingException e ) {
64
+ logger .log (Level .WARNING , e .getMessage (), e );
65
+ continue ;
100
66
}
67
+ // 以文件的方式扫描整个包下的文件 并添加到集合中
68
+ findClassesByFileSystem (packageName , filePath , true , classes );
69
+ } else if ("jar" .equals (protocol )) {
70
+ // 如果是jar包文件
71
+ // 定义一个JarFile
72
+ logger .fine ("scan jar package" );
73
+ JarFile jar = null ;
74
+ // 获取jar
75
+ try {
76
+ jar = ((JarURLConnection ) url .openConnection ()).getJarFile ();
77
+ } catch (IOException e ) {
78
+ logger .log (Level .WARNING , "jar scan error" , e );
79
+ continue ;
80
+ }
81
+ findClassesByJar (jar , packageName , true , classes );
101
82
}
102
- } catch (IOException e ) {
103
- e .printStackTrace ();
104
- logger .log (Level .SEVERE , "获取类信息失败" , e );
105
83
}
106
84
return classes ;
107
85
}
108
86
109
87
/**
110
- * 以文件的形式来获取包下的所有Class
88
+ * 以文件的形式来获取包下的所有类实例
111
89
*
112
- * @param packageName
113
- * @param packagePath
114
- * @param recursive
115
- * @param classes
90
+ * @param packageName 包名,用于classLoader加载
91
+ * @param filePath 查找类的目录
92
+ * @param recursive 递归查找
93
+ * @param classes 存放类实例的集合
116
94
*/
117
- public static void findAndAddClassesInPackageByFile (String packageName , String packagePath , final boolean recursive ,
95
+ public static void findClassesByFileSystem (String packageName , String filePath , final boolean recursive ,
118
96
Set <Class <?>> classes ) {
119
- // 获取此包的目录 建立一个File
120
- File dir = new File (packagePath );
97
+ File dir = new File (filePath );
121
98
// 如果不存在或者 也不是目录就直接返回
122
99
if (!dir .exists () || !dir .isDirectory ()) {
123
- logger .fine ("用户定义包名 " + packageName + " 下没有任何文件" );
100
+ logger .fine (String . format ( "用户定义包 {} 下没有任何文件", packageName ) );
124
101
return ;
125
102
}
126
103
// 如果存在 就获取包下的所有文件 包括目录
@@ -130,31 +107,76 @@ public boolean accept(File file) {
130
107
return (recursive && file .isDirectory ()) || (file .getName ().endsWith (".class" ));
131
108
}
132
109
});
133
- // 循环所有文件
134
- for (File file : dirfiles ) {
135
- // 如果是目录 则继续扫描
136
- if (file .isDirectory ()) {
137
- findAndAddClassesInPackageByFile (packageName + "." + file .getName (), file .getAbsolutePath (), recursive ,
138
- classes );
139
- } else {
140
- // 如果是java类文件 去掉后面的.class 只留下类名
141
- String className = file .getName ().substring (0 , file .getName ().length () - 6 );
142
- try {
143
- // 添加到集合中去
144
- // classes.add(Class.forName(packageName + '.' + className));
145
- // 这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净
146
- classes .add (
147
- Thread .currentThread ().getContextClassLoader ().loadClass (packageName + '.' + className ));
148
- } catch (ClassNotFoundException e ) {
149
- e .printStackTrace ();
150
- logger .log (Level .SEVERE , "添加用户自定义视图类错误 找不到此类的.class文件" , e );
110
+ if (dirfiles instanceof File []) {
111
+ // 循环所有文件
112
+ for (File file : dirfiles ) {
113
+ // 如果是目录 则继续扫描
114
+ if (file .isDirectory ()) {
115
+ findClassesByFileSystem (packageName + "." + file .getName (), file .getAbsolutePath (), recursive ,
116
+ classes );
117
+ } else {
118
+ // 如果是java类文件 去掉后面的.class 只留下类名
119
+ String className = file .getName ().substring (0 , file .getName ().length () - 6 );
120
+ try {
121
+ // 添加到集合中去
122
+ // classes.add(Class.forName(packageName + '.' + className));
123
+ // 这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净
124
+ classes .add (Thread .currentThread ().getContextClassLoader ()
125
+ .loadClass (packageName + '.' + className ));
126
+ } catch (ClassNotFoundException e ) {
127
+ logger .log (Level .INFO , "添加用户自定义视图类错误 找不到此类的.class文件" , e );
128
+ }
151
129
}
152
130
}
153
131
}
154
132
}
155
133
156
- /* public static void main(String[] args) {
157
- Set<Class<?>> set = getClasses("mine.frame");
158
- System.out.println(set);
159
- }*/
134
+ /**
135
+ * 从jar包中获取所有类的实例
136
+ *
137
+ * @param jar jar文件
138
+ * @param packageName 扫描的包路径
139
+ * @param recursive 递归查找
140
+ * @param classes 存放类实例的集合
141
+ */
142
+ public static void findClassesByJar (JarFile jar , String packageName , boolean recursive , Set <Class <?>> classes ) {
143
+ // 获取包的名字并进行替换
144
+ String packageDirName = packageName .replace ('.' , '/' );
145
+ // 从此jar包 得到一个枚举类
146
+ Enumeration <JarEntry > entries = jar .entries ();
147
+ // 同样的进行循环迭代
148
+ while (entries .hasMoreElements ()) {
149
+ // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
150
+ JarEntry entry = entries .nextElement ();
151
+ String name = entry .getName ();
152
+ // 如果是以/开头的
153
+ if (name .charAt (0 ) == '/' ) {
154
+ // 获取后面的字符串
155
+ name = name .substring (1 );
156
+ }
157
+ // 如果前半部分和定义的包名相同
158
+ if (name .startsWith (packageDirName )) {
159
+ int idx = name .lastIndexOf ('/' );
160
+ // 如果以"/"结尾 是一个包
161
+ if (idx != -1 ) {
162
+ // 获取包名 把"/"替换成"."
163
+ packageName = name .substring (0 , idx ).replace ('/' , '.' );
164
+ }
165
+ // 如果可以迭代下去 并且是一个包
166
+ if ((idx != -1 ) || recursive ) {
167
+ // 如果是一个.class文件 而且不是目录
168
+ if (name .endsWith (".class" ) && !entry .isDirectory ()) {
169
+ // 去掉后面的".class" 获取真正的类名
170
+ String className = name .substring (packageName .length () + 1 , name .length () - 6 );
171
+ try {
172
+ // 添加到classes
173
+ classes .add (Class .forName (packageName + '.' + className ));
174
+ } catch (ClassNotFoundException e ) {
175
+ logger .log (Level .INFO , packageName + '.' + className + " not found" , e );
176
+ }
177
+ }
178
+ }
179
+ }
180
+ }
181
+ }
160
182
}
0 commit comments