public void packageScan(String packaeName) throws Exception {
String path = packaeName.replace('.', '/');
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Enumeration<URL> urls = classLoader.getResources(path);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
if (url.getProtocol().equals("file")) {
File file = new File(url.toURI());
scanFile(file, packaeName);
} else if (url.getProtocol().equals("jar")) {
scanJar(url);
}
}
}
包扫描分对文件包和jar包两种扫描方式,首先由用户输入的包名获取URL,根据url.getProtocol()判断包协议。
文件包:
private void scanFile(File dir, String packageName) throws ClassNotFoundException {
File[] files = dir.listFiles();
for (File file : files) {
if (file.isDirectory()) {
scanFile(file, packageName + "." + file.getName());
} else if (file.isFile() && file.getName().endsWith(".class")) {
String className = packageName + "." + file.getName().replace(".class", "");
Class<?> klass = Class.forName(className);
dealClass(klass);
}
}
}
文件直接生成File,因为包名.文件名(去.class)为当前类路径,可通过反射获取该类。
文件包只需要该文件及包名称用于生成类。
jar包:
private void scanJar(URL url) throws IOException, ClassNotFoundException {
JarURLConnection connection = (JarURLConnection) url.openConnection();
JarFile jarFile = connection.getJarFile();
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (entry.isDirectory() || !entry.getName().endsWith(".class")) {
continue;
}
String className = entry.getName().replace(".class", "");
className = className.replace('/', '.');
Class<?> klass = Class.forName(className);
dealClass(klass);
}
}
jar包需要url获取连接、jarFile、entry(类比于File),连接就是获取进入包的权限,jarFile实际就是jar包,entries就是jar包下所有文件的包路径(包括类、包),再由包路径构造出类路径 反射即可。
当包扫描结合注释,包扫描用于扫描包下全部的类,而注解用于标注所需的类、方法、参数等,整个过程就是在包内筛选出被注解修饰过的东西。
因此通过该方法可替代xml、properties配置,原理都是在现成代码内查询所需要的东西。
xml配置相比于注解要更加繁琐、代码量更大,但是注解需要对源代码进行更改,固使用时还须结合当前情况进行判断。