天天看點

java 掃描指定包(包括jar包)

/*未經本人同意,禁止轉載。

做工程時,有時候需要掃描指定包,或者指定jar包,甚至掃描指定包下指定類,本文章詳細講解如何掃描,以及智能掃描,小編講的很詳細了仔細看。

以下講解, 包掃描和jar包掃描,自動識别包掃描還是jar包掃描。

//下文需要一個ClassLoader,
private ClassLoader classLoader;

	public PackageParse() {
	}
        
        //因為得到java檔案後我們需要把該檔案的類型傳回給使用者,使用者有該類型,
        //就可以得到成員,方法,注解,等等 ,是以提供一個抽象方法,給使用者傳回class<?>類型
	public abstract void dealClass(Class<?> klass);


//提供項目下的包比如  com.mec.util (或者提供com.mec.util.test.java)
//傳回值為PackageParse也就是本類型,是為了外部友善使用而已,無其他意思。
public PackageParse scanRoot(String packName) {
                //建立類加載器,不懂的可以百度學習下,以及classLoader.getResources
		this.classLoader = Thread.currentThread().getContextClassLoader();
                //packageName存放包名
		String packageName = "";
                //如果不含類即不是com.mec.util.test.java格式
		if(!packName.contains(".java")) {
                        //将包名字變成路徑
			packageName = packName.replace(".", "/");
		} else {
                        //是com.mec.util.test.java格式
                        //将路徑變為com/mec/util
			int lastIndex = packName.lastIndexOf(".");
			int secandIndex = packName.substring(0, lastIndex).lastIndexOf(".");
                        //設定包命為com.mec.util即為去掉.test.java
			packName = packName.substring(0, secandIndex);
                        //将路徑變為com/mec/util
			packageName = packName.substring(0, secandIndex).replace(".", "/");
		}
		
		try {    
                        //加載packageName的路徑傳回值為Enumeration<URL>類型
			Enumeration<URL> url = classLoader.getResources(packageName);
			//如果包名正确且不是空包,循環
			while(url.hasMoreElements()) {
				URL ur = url.nextElement();
                                //檢視url的類型
				String type = ur.getProtocol();
                                //如果是jar包類型
				if(type.equals("jar")) {
                                        //處理jarbao,方法在後面
					dealJar(ur);
                                //如果是file類型	
				} else if(type.equals("file")) {
                                      //URL轉換為file類型,File構造方法裡有File(URI uri)
					File file = new File(ur.toURI());
                                        //如果file是個目錄
					if(file.isDirectory()) {
                                                //調用處理目錄檔案
						dealFiles(packName, file);	
					} else {
                                                //處理檔案
						String name = file.getName();
                                                //如果是class檔案處理
						if(name.contains(".class")) {
                                                        //調用處理java類型的檔案也就是**.class,是我們想要的檔案
							deaJavaFile(file, packName);
						} else {
                                                //不是繼續循環
							continue;
						}
					}
				}	
			}	
		} catch (IOException e) {
			e.printStackTrace();
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
		
		return this;
	}

//處理目錄檔案
private void dealFiles(String packageName, File file) {	
                //安全期間判斷下檔案是否存在,存在的話進行操作
		if(file.exists()) {
                        //file一定是目錄型檔案是以得到該目錄下所有檔案周遊它們
			File[] files = file.listFiles();
			for(File childfile : files) {
                                //如果子檔案是目錄,則遞歸處理,調用本方法遞歸。
				if(childfile.isDirectory()) {
                                        //注意遞歸時候包名字要加上".檔案名"後為新的包名
                                        //因為後面反射時需要類名,也就是com.mec.***
					dealFiles(packageName + "." + childfile.getName(), childfile);
				} else {
                                //如果該檔案不是目錄。
					String name = childfile.getName();
                                        //該檔案是class類型
					if(name.contains(".class")) {
                                                處理它
						deaJavaFile(childfile, packageName);
					} else {
						continue;
					}
				}
			}	
		} else {
			return;
		}	
	}

//得到了我們想要的**.class檔案,處理它,我們希望傳回該類型即可。
private void deaJavaFile(File file, String packageName) {
                //以下操作得到類型
		int index = file.getName().lastIndexOf(".class");
		String filename = file.getName().substring(0, index);
		Class<?> klass = null;
		try {
			klass = Class.forName(packageName + "." + filename);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		//得到類型後,使用者怎麼使用這個類型是使用者的事情,和工具無關,是以提供一個抽象方法将klass傳過去
		dealClass(klass);
	}

//處理jar包類型
private void dealJar(URL url) {
                //以下六行都是處理jar的固定方法
		JarURLConnection jarURLConnection;
		try {
			jarURLConnection = (JarURLConnection) url.openConnection();
			JarFile jarFile = jarURLConnection.getJarFile();
			Enumeration<JarEntry> jarEntries = jarFile.entries();
			
			while(jarEntries.hasMoreElements()) {
				JarEntry jar = jarEntries.nextElement();
                                //如果是目錄,或者不是**.class類型不處理
				if(jar.isDirectory() || !jar.getName().endsWith(".class")) {
					continue;
				} 
                                //處理class類型
				String jarName = jar.getName();
				int dotIndex = jarName.indexOf(".class");
				String className = jarName.substring(0, dotIndex).replace("/", ".");
				Class<?> klass = Class.forName(className);
                                //調用抽象方法,給使用者傳回Class<?>類型
				dealClass(klass);
			}
				
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
	}
//以上為智能掃描,在提供一個普通掃描方法
//需要檔案的絕對路徑,和該項目下的包名字
public PackageParse scanClassPath(String absolute,String root) { 
		File file = new File(absolute);
		if(file.exists()) {
			if(file.isFile()) {
				if(file.getName().endsWith(".java")){
					int index = file.getName().lastIndexOf(".java");
					String filename = file.getName().substring(0, index);
					Class<?> klass = null;
					try {
						klass = Class.forName(root + "." + filename);
						dealClass(klass);
					} catch (ClassNotFoundException e) {
						e.printStackTrace();
					}
				}	
			}
		} 
		return this;
	}
           

以上為代碼展示下用法

java 掃描指定包(包括jar包)
java 掃描指定包(包括jar包)