@[TOC]加载指定包的类对象到容器
package com.ruoyi.project.tool.nio;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
//import org.apache.ibatis.io.Resources;
//import java.io.FileFilter;
//import java.net.URL;
/**
* 加载指定包下的类
* @author David
*/
public class LoadClassUtils {
/**
* 加载指定包
*
* @param packagePath
* @throws IOException
* @throws ClassNotFoundException
*/
public static void loadSpeckLoad(String packagePath) throws IOException, ClassNotFoundException {
String filePath = ClassLoader.getSystemResource("com/ruoyi/project").getPath();
File packageFile = new File(filePath);
Map<String, Class> map = new HashMap<>();
loadBean(map, packageFile, packagePath);
for (Map.Entry<String, Class> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
System.out.println(key + value);
}
}
/**
* 递归加载类信息
*
* @param map 存放加载对象的容器map
* @param file 加载的对象文件
* @param packageName - 文件的包名 例如com.weyao.saas(这个参数是必须要传的,不传的话会导致遍历到目录,class文件不知道在哪个包下)
* @throws ClassNotFoundException
*/
public static void loadBean(Map<String, Class> map, File file, String packageName) throws ClassNotFoundException {
// 目录处理
if (file.isDirectory()) {
// 获取目录下的文件对象信息
File[] files = file.listFiles(new FilenameFilter() {
// 对文件进行过滤(获取目录及以.class结尾的文件)
@Override
public boolean accept(File dir, String name) {
if (file.isDirectory() || (file.isFile() && file.getName().endsWith(".class"))) {
return true;
}
return false;
}
});
// 遍历目录下的文件
for (File subFile : files) {
// 如果是仍然是目录
if (subFile.isDirectory()) {
// 获取目录名称,例如common、service这种目录名称
String subPackageName = subFile.getName();
loadBean(map, subFile, packageName + "." + subPackageName);
} else {
// 如果是.class文件
loadBean(map, subFile, packageName);
}
}
} else {
// 判断为文件不再递归直接实例化
if (file.isFile() && file.getName().endsWith(".class")) {
String fileName = file.getName();
System.out.println(fileName);
System.out.println(fileName.lastIndexOf(".class"));
String className = fileName.substring(0, fileName.lastIndexOf("."));
Class<?> aClass = Class.forName(packageName + "." + className);
map.put(className, aClass);
}
}
}
// /**
// * 另一种将包名转化文件对象的方式(但是这个Resources是org.apache.ibatis.io包下的)
// * 如果有兴趣可以添加Maven依赖玩一下
// */
// public void getPackagePath(String packagePath) throws IOException, ClassNotFoundException {
// URL resourceURL = Resources.getResourceURL(packagePath.replace(".","/"));
// String protocol = resourceURL.getProtocol();
// if("file".equals(protocol)) {
// String filePath = resourceURL.getFile();
// File packageFile = new File(filePath);
// Map<String, Class> map = new HashMap<>();
// loadBean(map, packageFile, packagePath);
// }else {
// TODO 对jar包的解析处理
// }
// }
public static void main(String[] args) throws IOException, ClassNotFoundException {
String packagePath = "com.ruoyi.project";
loadSpeckLoad(packagePath);
}
}
小结:三个关键点吧
1 将指定包转换为File或转化为URL再转化为File
2 对层层嵌套的文件,需要采用递归(自己调自己)去处理
3 递归的方法中需要传包名
意义:Spring不就有个扫描指定包的标签吗?例如<context:component-scan base-package="cn.edu.dao"/>
。首先通过定义这个指定包,Spring就能帮你把指定包下的定义了@Controller、@Service、@Component,@Repository的类转化为bean对象。然后它就是通过你定义的指定包,然后帮你扫描指定包下的所有.class文件,然后反射得到它的类对象,这样它就掌握了这个类的所有结构信息,当然也包括是否有@Controller、@Service这样的注解,最后Spring框架判断类对象有这种注解,它就会去实例化这个类,然后将实例化的对象加载到容器中。