【Java】包扫描与Jar包扫描工具

为什么要用到包扫描? 

         包扫描一般用作于扫描出该包内所有带有某注解的类,并对之进行处理

         包扫描可分为普通包扫描和Jar包扫描


包扫描工具代码:

1.普通包扫描

    // 给定包名及当前文件currentfile
    private void scanPackage(String packageName, File currentfile) { 

                // 获得currentfile内的所有文件
		File[] files = currentfile.listFiles(new FileFilter() {	

                        // 内部类方法:根据路径名判断当前是否是文件夹
                        // 是则返回true
                        // 否则要判断该文件是否是class类型文件,并返回结果		
			@Override
			public boolean accept(File pathname) {
				if (currentfile.isDirectory()) {
					return true;
				}
				return pathname.getName().endsWith(".class");
			}
		});

                // 遍历所有的file
                // 若file是文件夹,则更新路径,递归扫描
		for (File file : files) {
			if (file.isDirectory()) {
				scanPackage(packageName + "." + file.getName(), file);
			} else {
                                // 若file非文件夹
                                // 则要根据目前包路径和file名得到类名
                                // 我们的包扫描是处理类的:
                                // 所以我不希望他是八大基本类型,注解,接口,及,枚举
				String fileName = file.getName().replace(".class", "");
				String className = packageName + "." + fileName;				
				try {
					Class<?> klass = Class.forName(className);
					if (klass.isAnnotation()
							||klass.isInterface()
							||klass.isEnum()
							||klass.isPrimitive()) {
						continue;
					}                  
                                        // 无论普通包扫描和Jar包扫描
                                        // 我们都需要对扫描到的类进行处理
                                        // 如何处理并不由我们扫描的工具决定
                                        // 是由工具使用者决定的
                                        // 所以下面的dealClass必然是抽象方法!
					dealClass(klass);
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
			}
		}
		
	}

 2.Jar包扫描

Jar包扫描的思路同普通包扫描

根据Jar包文件找出所有的类,当然要排除八大基本类型,接口,枚举和注解。

然后在通过用户完成对扫描出的class操作

	private void scanPackage(URL url) throws IOException {
		JarURLConnection jarUrlConnection =  (JarURLConnection) url.openConnection();
		JarFile jarFile = jarUrlConnection.getJarFile();
		Enumeration<JarEntry> jarEntries = jarFile.entries();
		
		while (jarEntries.hasMoreElements()) {
			JarEntry jarEntry = jarEntries.nextElement();
			String jarName = jarEntry.getName();
			if (jarEntry.isDirectory() || !jarName.endsWith(".class")) {
				continue;
			}
			String className = jarName.replace(".class", "").replaceAll("/", ".");
			try {
				Class<?> klass = Class.forName(className);
				if (klass.isAnnotation()
						||klass.isInterface()
						||klass.isEnum()
						||klass.isPrimitive()) {
					continue;
				}
				dealClass(klass);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		}
	}

3.当然,这样还不够“智能”。我能不能根据使用者给我的路径,“智能”判断其在扫描包还是Jar包,答案是肯定的。毕竟上面的都是private

	    // 重载:根据类进行类所在包的包扫描
        public void packageScanner(Class<?> klass) {
		packageScanner(klass.getPackage().getName());
	}
	
        // 根据包名进行包扫描
	public void packageScanner(String packageName) {
                // 将包名转换为路径
		String packagePath = packageName.replace(".", "/");
		        // 得到当前类加载器
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
	    try {
                    // 遍历路径下的所有,得到URL,根据URL判断其属性是否Jar
                    // 达到不同处理的目的
			Enumeration<URL> resources = classLoader.getResources(packagePath);
			while (resources.hasMoreElements()) {
				URL url = resources.nextElement();
				if (url.getProtocol().equals("jar")) {
					scanPackage(url);
				} else {			
					File file = new File(url.toURI());
					if (!file.exists()) {
						continue;
					}
					scanPackage(packageName, file);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
	}

整体代码 

import java.io.File;
import java.io.FileFilter;
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 abstract class PackageScanner {
	
	public PackageScanner() {
	}
	
	public abstract void dealClass(Class<?> klass);
	
	public void packageScanner(Class<?> klass) {
		packageScanner(klass.getPackage().getName());
	}
	
	public void packageScanner(String packageName) {
		String packagePath = packageName.replace(".", "/");
		
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
	    try {
			Enumeration<URL> resources = classLoader.getResources(packagePath);
			while (resources.hasMoreElements()) {
				URL url = resources.nextElement();
				if (url.getProtocol().equals("jar")) {
					scanPackage(url);
				} else {			
					File file = new File(url.toURI());
					if (!file.exists()) {
						continue;
					}
					scanPackage(packageName, file);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
	}
	
	private void scanPackage(URL url) throws IOException {
		JarURLConnection jarUrlConnection =  (JarURLConnection) url.openConnection();
		JarFile jarFile = jarUrlConnection.getJarFile();
		Enumeration<JarEntry> jarEntries = jarFile.entries();
		
		while (jarEntries.hasMoreElements()) {
			JarEntry jarEntry = jarEntries.nextElement();
			String jarName = jarEntry.getName();
			if (jarEntry.isDirectory() || !jarName.endsWith(".class")) {
				continue;
			}
			String className = jarName.replace(".class", "").replaceAll("/", ".");
			try {
				Class<?> klass = Class.forName(className);
				if (klass.isAnnotation()
						||klass.isInterface()
						||klass.isEnum()
						||klass.isPrimitive()) {
					continue;
				}
				dealClass(klass);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		}
	}

	private void scanPackage(String packageName, File currentfile) { 
		File[] files = currentfile.listFiles(new FileFilter() {			
			@Override
			public boolean accept(File pathname) {
				if (currentfile.isDirectory()) {
					return true;
				}
				return pathname.getName().endsWith(".class");
			}
		});
		for (File file : files) {
			if (file.isDirectory()) {
				scanPackage(packageName + "." + file.getName(), file);
			} else {
				String fileName = file.getName().replace(".class", "");
				String className = packageName + "." + fileName;				
				try {
					Class<?> klass = Class.forName(className);
					if (klass.isAnnotation()
							||klass.isInterface()
							||klass.isEnum()
							||klass.isPrimitive()) {
						continue;
					}
					dealClass(klass);
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
			}
		}
		
	}
}

 

 

 除构造方法外,提供两个public方法 void packageScanner(Class<?> klass) 

                                                       void packageScanner(String packageName)

扫描出  给定类所在包  或  给定包路径  下的所有的类 (用到递归)

用抽象方法提供给工具使用者去决定 如何处理扫描出的类

 

使用方法:

	public static void main(String[] args) {
		new PackageScanner() {			
			@Override
			public void dealClass(Class<?> klass) {
				System.out.println(klass.getName());
			}
		}.packageScanner("util.core");
	}

    或

	public static void main(String[] args) {
		new PackageScanner() {
			
			@Override
			public void dealClass(Class<?> klass) {
				System.out.println(klass.getName());
			}
		}.packageScanner(XXX.class);
	}

 

全部评论

相关推荐

不愿透露姓名的神秘牛友
11-20 19:57
已编辑
某大厂 golang工程师 23.0k*16.0, 2k房补,年终大概率能拿到
点赞 评论 收藏
分享
找不到工作死了算了:没事的,雨英,hr肯主动告知结果已经超越大部分hr了
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务