模拟数据库ORM之包扫描工具

本文介绍了如何使用JAVA包扫描技术解决数据库ORM中多表处理的不便,通过一键扫描指定包内的所有类,获取注解信息。内容包括普通包扫描和jar包扫描的思路,以及代码实现中根据URL协议区分处理的方法。包扫描工具不仅方便了ORM的注解使用,也适用于反射机制。
摘要由CSDN通过智能技术生成

一、前言

数据库,表与对象映射关系,可以通过解析XML配置文件或使用注解方法获取。两者相较,注解优势是,使用方便,解析代码简单易实现。但当处理多张表时,就需要手动指定扫描多个类,相当麻烦。为了解决这一缺陷,JAVA包扫描技术,可以一键式扫描指定父包及子包内所有类,获取注解信息。

二、思路简述

1. 普通包扫描

	1.获取文件包路径、类加载器。
	2.类加载器根据包路路径获取url集合。
	3.根据url创建File包文件对象,获取包内Class文件或包文件。
	4.针对Class,截取类名,并实例化交付类处理方法。
	5.针对包文件,递归处理获取包内Class文件或包文件。

2. jar包扫描

	1.获取文件包路径、类加载器。。
	2.类加载器根据包路路径获取url集合。
	3.根据url建立远程连接JarURLConnection,获取包资源JarFile对象。
	4.通过JarFile,获取文件名与文件对应关系Entry
	5.根据Entry获取文件名,截取类名,并实例化交付类处理方法。

三、代码实现

在代码实现过程中发现,Jar包资源定位符URL是以“jar”开头,普通包是"file",那么可以根据协议名称分别处理。因此可以统一实现jar包和普通包扫描。

public abstract class PackageScan {

	public PackageScan() {
	}

	public void scanPackage(String packageName) {
		//1.获取文件包路径、类加载器。
		String path = packageName.replace('.', '/');
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

		try {
			//	2.类加载器根据包路路径获取url集合。
			Enumeration<URL> urls = classLoader.getResources(path);
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				//获取协议名称
				String protocol = url.getProtocol();
				if (protocol.equalsIgnoreCase("file")) {
					File file = new File(url.toURI());
					dealPackage(file, packageName);
				} else if (protocol.equalsIgnoreCase("jar")) {
					dealJarFile(path, url);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
	}
	
	private void dealPackage(File curFile, String packageName) {
		//3.获取包内Class文件或包文件。
		File[] files = curFile.listFiles();
		for (File file : files) {
			String fileName = file.getName();	
			//4.针对Class,截取类名,并实例化交付类处理方法。
			if (file.isFile() && fileName.endsWith(".class")) {
				String className = packageName + "." + fileName.replace(".class", "");
				try {
					Class<?> klass = Class.forName(className);
					dealClass(klass);
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
			} else {
				//5.针对包文件,递归获取包内Class文件或包文件。
				dealPackage(file, packageName + "." + file.getName());
			}
		}
	}

	private void dealJarFile(String jarPackagePath, URL url) {
		try {
			//3.根据url建立远程连接JarURLConnection,获取包资源JarFile对象。
			JarURLConnection jarUrlconnection = (JarURLConnection) url.openConnection();
			JarFile jarFileContain = jarUrlconnection.getJarFile();
			//	4.通过JarFile,获取文件名与文件对应关系Entry
			Enumeration<JarEntry> filesEntries = jarFileContain.entries();
			while (filesEntries.hasMoreElements()) {
				JarEntry jarEntry = filesEntries.nextElement();
				//5.根据Entry获取文件名,截取类名,并实例化交付类处理方法。
				String fileName = jarEntry.getName();
				if (fileName.endsWith(".class") && fileName.startsWith(jarPackagePath)) {
					try {
						String classPath = fileName.replace(".class", "");
						String className = classPath.replace('/', '.');
						Class<?> klass = Class.forName(className);
						dealClass(klass);
					} catch (ClassNotFoundException e) {
						e.printStackTrace();
					}
				}
			}
		} catch (IOException e2) {
			e2.printStackTrace();
		}
	}

	protected abstract void dealClass(Class<?> klass);
}

四、后话

包扫描工具解决了批量类扫描。此工具不仅限于注解使用,也可以用于反射机制等方面。笔者首次在扫描Jar包时,有的jar包无任何反应,最后发现是打Jar包时,没有Add directory entries。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值