Java包扫描(包含Jar包的扫描)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_43504844/article/details/101440541

包扫描的本质

包扫描的实质扫描的是所给包中的class文件,且jar包用普通包的扫描方法来扫描是不正确的。

实现包扫描的核心思路

给出一个需要扫描的包的名称,首先进行判断,该包是jar包还是普通包
	public void packageScann(String PackageName) {
		String rootname = "";
		//将包名转换为目录形式
		rootname = PackageName.replace('.', '/');
		//通过给出的包名转换成的目录名称得到当前目录的URL
		URL url = Thread.currentThread().getContextClassLoader().getResource(rootname);
		//通过url.getProtocol().equals()方法来判断是File文件目录还是Jar包
		if (url.getProtocol().equals("file")) {
			try {
				URI uri = url.toURI();
				File file = new File(uri);
				//已检测是目录路径,通过dealDirectory()方法来处理
				dealDirectory(PackageName, file);
			} catch (URISyntaxException e) {
				e.printStackTrace();
			}					
		} else if (url.getProtocol().equals("jar")) {
			//否则是jar包,通过dealJarPackage()方法来处理,此方法只需URL作为参数
			dealJarPackage(url);
		}
	}

处理普通包

处理目录路径dealDirectory()此时分成两种情况:一是已经是java的class文件,二是仍然未到最底层还是目录

public void dealDirectory(String PackageName, File file) {
		//通过当前目录即参数中的File类型的file,可以得到当前目录下的所有文件
		File[] fileList = file.listFiles();
		//便利这个list,以此处理每一个file
		for (File files : fileList) {
			//判断是否仍是目录路径,若是,调用dealDirectory()方法
			if (files.isDirectory()) {
				//但对于参数中的PackageName路径要增加一层,即在末尾追加“.files.getName()”,一定要注意不能省略中间的“.”
				dealDirectory(PackageName + "." + files.getName(), files);
			}
			//此时判断是否已经是class文件,即不再是目录,已经不再有分支
			else if (files.isFile()){
				//处理class文件
				dealClassFile(PackageName, files);
			}
			
		}
	}

当前已经是ClassFile,进行对该class的完善处理

	public void dealClassFile(String packageName, File file) {
		//此时通过file.getName()得到的是文件名,形式为:XXX.XXXX
		String className = file.getName();
		//判断一下是否为class文件,即是否以".class"结尾
		if (className.endsWith(".class")) {
			//将末尾的.class去掉
			className = className.replace(".class", "");
				try {
					//这里通过反射机制,处理经过完善的该class文件的名字(此时已经是该class文件多对应的类名)
					Class<?> klass = Class.forName(packageName + "." + className);
					//调用dealClass()方法,该方法是一个抽象方法,需要在用户使用该工具时对其进行实现,可以在不同的场景下有不同的处理方式
					dealClass(klass);
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
		}
	}

其中有一个抽象方法dealClass,是在已经到了目录最底层的class文件之后,通过对class文件获取名字,进行完善,即前面加上包名,形成一个完整的类名,通过反射机制反射出该类的类型,对于后序得到的Class<?>的通过抽象方法来扩展工具的适用范围,用户根据需求来做不同的处理

处理Jar包

jar包需要特殊处理,根据代码进行解析	
	private void dealJarPackage(URL url) {
		try {
			//JarURLConnection类通过JAR协议建立了一个访问 jar包URL的连接,可以访问这个jar包或者这个包里的某个文件
			JarURLConnection connection = (JarURLConnection) url.openConnection();
			//通过这个连接进一步先得到JarFile
			JarFile jarFile = connection.getJarFile();
			//得到该JarFile目录下所有项目
			Enumeration<JarEntry> jarEntries = jarFile.entries();
			//遍历得到的jarEntries 
			while (jarEntries.hasMoreElements()) {
				JarEntry jar = jarEntries.nextElement();
				//如果是目录路径或者不是class文件,不予处理
				if(jar.isDirectory() || !jar.getName().endsWith(".class")) {
					continue;
				}
				//以上是对于Jar包的特殊处理,由于Jar包与普通包不一样,其中一些文件也不能直接以普通文件的方式来处理
				
				//以下与前面处理的方式一样
				String jarName = jar.getName();
				jarName = jarName.replace(".class", "");
				jarName = jarName.replace("/", ".");
				
				try {
					Class<?> klass = Class.forName(jarName);
					dealClass(klass);
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	

以上是对于包扫描的分段解析,下面附上全部代码:

public abstract class PackageScanner {
	
	public PackageScanner() {
	}
	
	public abstract void dealClass(Class<?> klass);
	
	public void dealClassFile(String packageName, File file) {
		//此时通过file.getName()得到的是文件名,形式为:XXX.XXXX
		String className = file.getName();
		//判断一下是否为class文件,即是否以".class"结尾
		if (className.endsWith(".class")) {
			//将末尾的.class去掉
			className = className.replace(".class", "");
				try {
					//这里通过反射机制,处理经过完善的该class文件的名字(此时已经是该class文件多对应的类名)
					Class<?> klass = Class.forName(packageName + "." + className);
					//调用dealClass()方法,该方法是一个抽象方法,需要在用户使用该工具时对其进行实现,可以在不同的场景下有不同的处理方式
					dealClass(klass);
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
		}
	}
	
	private void dealJarPackage(URL url) {
		try {
			//JarURLConnection类通过JAR协议建立了一个访问 jar包URL的连接,可以访问这个jar包或者这个包里的某个文件
			JarURLConnection connection = (JarURLConnection) url.openConnection();
			//通过这个连接进一步先得到JarFile
			JarFile jarFile = connection.getJarFile();
			//得到该JarFile目录下所有项目
			Enumeration<JarEntry> jarEntries = jarFile.entries();
			//遍历得到的jarEntries 
			while (jarEntries.hasMoreElements()) {
				JarEntry jar = jarEntries.nextElement();
				//如果是目录路径或者不是class文件,不予处理
				if(jar.isDirectory() || !jar.getName().endsWith(".class")) {
					continue;
				}
				//以上是对于Jar包的特殊处理,由于Jar包与普通包不一样,其中一些文件也不能直接以普通文件的方式来处理
				
				//以下与前面处理的方式一样
				String jarName = jar.getName();
				jarName = jarName.replace(".class", "");
				jarName = jarName.replace("/", ".");
				
				try {
					Class<?> klass = Class.forName(jarName);
					dealClass(klass);
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void dealDirectory(String PackageName, File file) {
		//通过当前目录即参数中的File类型的file,可以得到当前目录下的所有文件
		File[] fileList = file.listFiles();
		//便利这个list,以此处理每一个file
		for (File files : fileList) {
			//判断是否仍是目录路径,若是,调用dealDirectory()方法
			if (files.isDirectory()) {
				//但对于参数中的PackageName路径要增加一层,即在末尾追加“.files.getName()”,一定要注意不能省略中间的“.”
				dealDirectory(PackageName + "." + files.getName(), files);
			}
			//此时判断是否已经是class文件,即不再是目录,已经不再有分支
			else if (files.isFile()){
				//处理class文件
				dealClassFile(PackageName, files);
			}
			
		}
	}
	public void packageScann(String PackageName) {
		String rootname = "";
		//将包名转换为目录形式
		rootname = PackageName.replace('.', '/');
		//通过给出的包名转换成的目录名称得到当前目录的URL
		URL url = Thread.currentThread().getContextClassLoader().getResource(rootname);
		//通过url.getProtocol().equals()方法来判断是File文件目录还是Jar包
		if (url.getProtocol().equals("file")) {
			try {
				URI uri = url.toURI();
				File file = new File(uri);
				//已检测是目录路径,通过dealDirectory()方法来处理
				dealDirectory(PackageName, file);
			} catch (URISyntaxException e) {
				e.printStackTrace();
			}					
		} else if (url.getProtocol().equals("jar")) {
			//否则是jar包,通过dealJarPackage()方法来处理,此方法只需URL作为参数
			dealJarPackage(url);
		}
	}
}

测试如下

com.mec.Complex为测试所用的类
结果为
Test类对于一些进行了输出测试

猜你喜欢

转载自blog.csdn.net/weixin_43504844/article/details/101440541