文章目录
- 前言
- 包扫描
- 实现思路(需求分析):
- 具体实现
- 完整代码
前言
注解在 Java 是一个非常重要的存在,而且它出现的非常频繁。
在一个工程下可能有许多的包或者Jar包,为了结合注解可以准确的定位到一个需要的类上,并且扫描到一个包下的所有类方便我们使用反射机制,所以产生了包扫描工具实现的想法,它可以帮我们找到带有注解的类,再通过反射执行。
包扫描
我们可以通过用户提供的包名,扫描该包下的所有类。
实现思路(需求分析):
通过博主思考,我们需要实现功能:
-
一个工程下存在普通包或者Jar包,分开处理 Jar 包和普通包;
-
得到该包下我们所要找的类(例如:带有注解的类或者接口或者枚举类型等)这里主要用于扫描带有注解的类。
因为通过包扫描找到该类,我们可以通过注解信息得到该类里面带有注解的成员或方法的信息,然后通过反射机制执行。
具体实现
- 创建一个
IClassDealer
接口:
public interface IClassDealer {void classDealer(Class<?> klass);
}
-
包扫描类实现:
-
这里根据包名,通过得到 url 协议名称,然后判断是 Jar 包还是普通包,如果是普通包就调用
fileScan(String packageName, File dir)
这个方法,进行普通包扫描,如果是 Jar 包,就调用jarScan(String packageName, URL url)
,进行 Jar 扫描。public void scanPackage(String packageName) throws URISyntaxException {String packagePath = packageName.replace(".", "/");URL url = Thread.currentThread().getContextClassLoader().getResource(packagePath);if (url.getProtocol().equals("file")) {File root = new File(url.toURI());fileScan(packageName, root);} else if (url.getProtocol().equals("jar")) {try {jarScan(packageName, url);} catch (IOException e) {e.printStackTrace();}}}
-
普通包扫描
private void fileScan(String packageName, File dir) {File[] files = dir.listFiles();for (File file : files) {if (file.isDirectory()) {fileScan(packageName + "." + file.getName(), file);} else {String fileName = file.getName();if (!fileName.endsWith(".class") || fileName.contains("$")) {continue;}fileName = fileName.replace(".class", "");String className = packageName + "." + fileName;try {Class<?> klass = Class.forName(className);classDealer.classDealer(klass);} catch (ClassNotFoundException e) {e.printStackTrace();continue;}}}}
-
Jar 扫描
private void jarScan(String packageName, URL url) throws IOException {JarURLConnection connection = (JarURLConnection) url.openConnection();JarFile jarFile = connection.getJarFile();Enumeration<JarEntry> entries = jarFile.entries();while (entries.hasMoreElements()) {JarEntry entry = entries.nextElement();String entryName = entry.getName();String className = entryName.replace("/", ".");if (!className.startsWith(packageName) || className.contains("$") || !entryName.endsWith(".class")) {continue;}className = className.replace(".class", "");try {Class<?> klass = Class.forName(className);classDealer.classDealer(klass);} catch (ClassNotFoundException e) {e.printStackTrace();}}}
-
完整代码
- 创建一个
IClassDealer
接口:
public interface IClassDealer {void classDealer(Class<?> klass);
}
- 包扫描具体代码:
package com.hb.util;import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;public class PackageScanner {/***因为扫描到的类的相关具体操作不是本工具需要完成的,*因此给一个接口,具体操作由工具使用者完成。*用这个方法可以去筛选使用者需要扫描的包下的类达到自己的目的。*/private IClassDealer classDealer;public PackageScanner() {this.classDealer = new IClassDealer() {@Overridepublic void classDealer(Class<?> klass) {}};}public PackageScanner addClassDealer(IClassDealer classDealer) {this.classDealer = classDealer;return this;}public void scanPackage(String packageName) throws URISyntaxException {String packagePath = packageName.replace(".", "/");URL url = Thread.currentThread().getContextClassLoader().getResource(packagePath);if (url.getProtocol().equals("file")) {File root = new File(url.toURI());fileScan(packageName, root);} else if (url.getProtocol().equals("jar")) {try {jarScan(packageName, url);} catch (IOException e) {e.printStackTrace();}}}private void jarScan(String packageName, URL url) throws IOException {JarURLConnection connection = (JarURLConnection) url.openConnection();JarFile jarFile = connection.getJarFile();Enumeration<JarEntry> entries = jarFile.entries();while (entries.hasMoreElements()) {JarEntry entry = entries.nextElement();String entryName = entry.getName();String className = entryName.replace("/", ".");if (!className.startsWith(packageName) || className.contains("$") || !entryName.endsWith(".class")) {continue;}className = className.replace(".class", "");try {Class<?> klass = Class.forName(className);classDealer.classDealer(klass);} catch (ClassNotFoundException e) {e.printStackTrace();}}}private void fileScan(String packageName, File dir) {File[] files = dir.listFiles();for (File file : files) {if (file.isDirectory()) {fileScan(packageName + "." + file.getName(), file);} else {String fileName = file.getName();if (!fileName.endsWith(".class") || fileName.contains("$")) {continue;}fileName = fileName.replace(".class", "");String className = packageName + "." + fileName;try {Class<?> klass = Class.forName(className);classDealer.classDealer(klass);} catch (ClassNotFoundException e) {e.printStackTrace();continue;}}}}
}
测试运行结果:
