文章目录
前言
注解在 Java 是一个非常重要的存在,而且它出现的非常频繁。
在一个工程下可能有许多的包或者Jar包,为了结合注解可以准确的定位到一个需要的类上,并且扫描到一个包下的所有类方便我们使用反射机制,所以产生了包扫描工具实现的想法,它可以帮我们找到带有注解的类,再通过反射执行。
包扫描
我们可以通过用户提供的包名,扫描该包下的所有类。
实现思路(需求分析):
通过博主思考,我们需要实现功能:
-  一个工程下存在普通包或者Jar包,分开处理 Jar 包和普通包; 
-  得到该包下我们所要找的类(例如:带有注解的类或者接口或者枚举类型等)这里主要用于扫描带有注解的类。 
因为通过包扫描找到该类,我们可以通过注解信息得到该类里面带有注解的成员或方法的信息,然后通过反射机制执行。
具体实现
- 创建一个 IClassDealer接口:
public interface IClassDealer {
	void classDealer(Class<?> klass);
}
-  包扫描类实现: -  这里根据包名,通过得到 url 协议名称,然后判断是 Jar 包还是普通包,如果是普通包就调用 fileScan(String packageName, File dir)这个方法,进行普通包扫描,如果是 Jar 包,就调用jarScan(String packageName, URL url),进行 Jar 扫描。public void scanPackage(String packageName) throws URISyntaxException { String packagePath = packageName.replace(".", "/"); URL url = Thread.currentThread().getContextClassLoader().getResource(packagePath); if (url.getProtocol().equals("file")) { File root = new File(url.toURI()); fileScan(packageName, root); } else if (url.getProtocol().equals("jar")) { try { jarScan(packageName, url); } catch (IOException e) { e.printStackTrace(); } } }
-  普通包扫描 private void fileScan(String packageName, File dir) { File[] files = dir.listFiles(); for (File file : files) { if (file.isDirectory()) { fileScan(packageName + "." + file.getName(), file); } else { String fileName = file.getName(); if (!fileName.endsWith(".class") || fileName.contains("$")) { continue; } fileName = fileName.replace(".class", ""); String className = packageName + "." + fileName; try { Class<?> klass = Class.forName(className); classDealer.classDealer(klass); } catch (ClassNotFoundException e) { e.printStackTrace(); continue; } } } }
-  Jar 扫描 private void jarScan(String packageName, URL url) throws IOException { JarURLConnection connection = (JarURLConnection) url.openConnection(); JarFile jarFile = connection.getJarFile(); Enumeration<JarEntry> entries = jarFile.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); String entryName = entry.getName(); String className = entryName.replace("/", "."); if (!className.startsWith(packageName) || className.contains("$") || !entryName.endsWith(".class")) { continue; } className = className.replace(".class", ""); try { Class<?> klass = Class.forName(className); classDealer.classDealer(klass); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
 
-  
完整代码
- 创建一个 IClassDealer接口:
public interface IClassDealer {
	void classDealer(Class<?> klass);
}
- 包扫描具体代码:
package com.hb.util;
import java.io.File;
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 class PackageScanner {
    /**
    *因为扫描到的类的相关具体操作不是本工具需要完成的,
	*因此给一个接口,具体操作由工具使用者完成。
	*用这个方法可以去筛选使用者需要扫描的包下的类达到自己的目的。
    */
	private IClassDealer classDealer;
	
	public PackageScanner() {
		this.classDealer = new IClassDealer() {
			@Override
			public void classDealer(Class<?> klass) {
			}
		};
	}
	public PackageScanner addClassDealer(IClassDealer classDealer) {
		this.classDealer = classDealer;
		return this;
	}
	public void scanPackage(String packageName) throws URISyntaxException {
		String packagePath = packageName.replace(".", "/");
		URL url = Thread.currentThread().getContextClassLoader().getResource(packagePath);
		if (url.getProtocol().equals("file")) {
			File root = new File(url.toURI());
			fileScan(packageName, root);
		} else if (url.getProtocol().equals("jar")) {
			try {
				jarScan(packageName, url);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	private void jarScan(String packageName, URL url) throws IOException {
		JarURLConnection connection = (JarURLConnection) url.openConnection();
		JarFile jarFile = connection.getJarFile();
		Enumeration<JarEntry> entries = jarFile.entries();
		while (entries.hasMoreElements()) {
			JarEntry entry = entries.nextElement();
			String entryName = entry.getName();
			String className = entryName.replace("/", ".");
			
			if (!className.startsWith(packageName) || className.contains("$") || !entryName.endsWith(".class")) {
				continue;
			}
			className = className.replace(".class", "");
			try {
				Class<?> klass = Class.forName(className);
				classDealer.classDealer(klass);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		}
	}
	
	private void fileScan(String packageName, File dir) {
		File[] files = dir.listFiles();
		for (File file : files) {
			if (file.isDirectory()) {
				fileScan(packageName + "." + file.getName(), file);
			} else {
				String fileName = file.getName();
				if (!fileName.endsWith(".class") || fileName.contains("$")) {
					continue;
				}
				fileName = fileName.replace(".class", "");
				String className = packageName  + "." + fileName;
				try {
					Class<?> klass = Class.forName(className);
					classDealer.classDealer(klass);
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
					continue;
				}
			}
		}
	}
}
测试运行结果:
 
                 
                   
                   
                   
                   
                             文章介绍了如何在Java中实现包扫描,通过扫描指定包下的类,特别是带有特定注解的类,以便后续使用反射机制进行处理。文章提供了从普通包和Jar包中扫描的实现代码,并通过接口`IClassDealer`让用户自定义处理找到的类。
文章介绍了如何在Java中实现包扫描,通过扫描指定包下的类,特别是带有特定注解的类,以便后续使用反射机制进行处理。文章提供了从普通包和Jar包中扫描的实现代码,并通过接口`IClassDealer`让用户自定义处理找到的类。
           
       
           
                 
                 
                 
                 
                 
                
               
                 
                 
                 
                 
                
               
                 
                 扫一扫
扫一扫
                     
                     
              
             
                   1147
					1147
					
 被折叠的  条评论
		 为什么被折叠?
被折叠的  条评论
		 为什么被折叠?
		 
		  到【灌水乐园】发言
到【灌水乐园】发言                                
		 
		 
    
   
    
   
             
					 
					 
					


 
            