在模拟实现Spring时我们需要知道哪些类上有Component注解从而生成其对象放如容器中,如何知道类上有Component注解?这里用到了包扫描。包扫描在扫描到类之后不仅可以判断类上是否有注解还可以进行其他操作(由用户定义实现),在这片文章中我们来说一下包扫描
public abstract class PackageScanner {
public PackageScanner() {
}
public void scanPackage(String packageName) {
//将包名转换为目录
String pathName = packageName.replace('.', '/');
//获取当前目录的URL
URL url = Thread.currentThread().getContextClassLoader().getResource(pathName);
//用url来判断要扫描的是普通包还是jar包
if(url.getProtocol().equals("file")) {
try {
//生成普通包的最后一级目录
File curFile = new File(url.toURI());
//对普通包进行扫描
dealPackage(curFile, packageName);
} catch (URISyntaxException e) {
e.printStackTrace();
}
}else if(url.getProtocol().equals("jar")) {
//对jar包进行扫描
dealJar(url);
}
}
//普通包扫描方法
private void dealPackage(File cur, String packageName) {
//获取最后一级目录的文件
File[] files = cur.listFiles();
//对获取的文件进行处理
for (File file : files) {
//判断是否是文件
if (file.isFile()) {
//如果文件名不以.class结尾则不予处理
//否则调用dealClass(klass)方法对扫描到的类进行处理
String fileName = file.getName();
if (!fileName.endsWith(".class")) {
continue;
}
fileName = fileName.replace(".class", "");
String className = packageName + "." + fileName;
try {
Class<?> klass = Class.forName(className);
dealClass(klass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} else {
//如果不是文件(目录),则递归调用普通包扫描方法
dealPackage(file, packageName + "." + file.getName());
}
}
}
private void dealJar(URL url) {
try {
//建立了访问 jar包URL的连接
JarURLConnection connection = (JarURLConnection) url.openConnection();
//通过连接得到JarFile
JarFile jarFile = connection.getJarFile();
//获取该JarFile目录下所有项目
Enumeration<JarEntry> entryList = jarFile.entries();
//遍历得到的jarEntries
while (entryList.hasMoreElements()) {
JarEntry jarEntry = entryList.nextElement();
//如果是目录或者不是class文件,不予处理
if (jarEntry.isDirectory() || !jarEntry.getName().endsWith(".class")) {
continue;
}
//调用dealClass(klass)方法对扫描到的类进行处理
String className = jarEntry.getName();
className = className.replace(".class", "");
className = className.replace('/', '.');
try {
Class<?> klass = Class.forName(className);
dealClass(klass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
//扫描到类之后的具体操作,由用户实现
public abstract void dealClass(Class<?> klass);
}