?????? 之前在看spring注解的時(shí)候,有看到再配置文件里面定義component scan package就能自動掃描對應(yīng)包下面的class,
然后根據(jù)注解生成相應(yīng)的bean。自己對這個(gè)功能很好奇,就搜了下,找到了實(shí)現(xiàn)的關(guān)鍵代碼,記錄下。后續(xù)再對這段代碼深入學(xué)習(xí)。
?
?
- /** ?
- ?????*?從包package中獲取所有的Class ?
- ?????*? ?
- ?????*?@param?pack ?
- ?????*?@return ?
- ?????*/ ??
- ???? public ? static ?Set<Class<?>>?getClasses(String?pack)?{ ??
- ??
- ???????? //?第一個(gè)class類的集合 ??
- ????????Set<Class<?>>?classes?=? new ?LinkedHashSet<Class<?>>(); ??
- ???????? //?是否循環(huán)迭代 ??
- ???????? boolean ?recursive?=? true ; ??
- ???????? //?獲取包的名字?并進(jìn)行替換 ??
- ????????String?packageName?=?pack; ??
- ????????String?packageDirName?=?packageName.replace( '.' ,? '/' ); ??
- ???????? //?定義一個(gè)枚舉的集合?并進(jìn)行循環(huán)來處理這個(gè)目錄下的things ??
- ????????Enumeration<URL>?dirs; ??
- ???????? try ?{ ??
- ????????????dirs?=?Thread.currentThread().getContextClassLoader().getResources( ??
- ????????????????????packageDirName); ??
- ???????????? //?循環(huán)迭代下去 ??
- ???????????? while ?(dirs.hasMoreElements())?{ ??
- ???????????????? //?獲取下一個(gè)元素 ??
- ????????????????URL?url?=?dirs.nextElement(); ??
- ???????????????? //?得到協(xié)議的名稱 ??
- ????????????????String?protocol?=?url.getProtocol(); ??
- ???????????????? //?如果是以文件的形式保存在服務(wù)器上 ??
- ???????????????? if ?( "file" .equals(protocol))?{ ??
- ????????????????????System.err.println( "file類型的掃描" ); ??
- ???????????????????? //?獲取包的物理路徑 ??
- ????????????????????String?filePath?=?URLDecoder.decode(url.getFile(),? "UTF-8" ); ??
- ???????????????????? //?以文件的方式掃描整個(gè)包下的文件?并添加到集合中 ??
- ????????????????????findAndAddClassesInPackageByFile(packageName,?filePath, ??
- ????????????????????????????recursive,?classes); ??
- ????????????????}? else ? if ?( "jar" .equals(protocol))?{ ??
- ???????????????????? //?如果是jar包文件 ??
- ???????????????????? //?定義一個(gè)JarFile ??
- ????????????????????System.err.println( "jar類型的掃描" ); ??
- ????????????????????JarFile?jar; ??
- ???????????????????? try ?{ ??
- ???????????????????????? //?獲取jar ??
- ????????????????????????jar?=?((JarURLConnection)?url.openConnection()) ??
- ????????????????????????????????.getJarFile(); ??
- ???????????????????????? //?從此jar包?得到一個(gè)枚舉類 ??
- ????????????????????????Enumeration<JarEntry>?entries?=?jar.entries(); ??
- ???????????????????????? //?同樣的進(jìn)行循環(huán)迭代 ??
- ???????????????????????? while ?(entries.hasMoreElements())?{ ??
- ???????????????????????????? //?獲取jar里的一個(gè)實(shí)體?可以是目錄?和一些jar包里的其他文件?如META-INF等文件 ??
- ????????????????????????????JarEntry?entry?=?entries.nextElement(); ??
- ????????????????????????????String?name?=?entry.getName(); ??
- ???????????????????????????? //?如果是以/開頭的 ??
- ???????????????????????????? if ?(name.charAt( 0 )?==? '/' )?{ ??
- ???????????????????????????????? //?獲取后面的字符串 ??
- ????????????????????????????????name?=?name.substring( 1 ); ??
- ????????????????????????????} ??
- ???????????????????????????? //?如果前半部分和定義的包名相同 ??
- ???????????????????????????? if ?(name.startsWith(packageDirName))?{ ??
- ???????????????????????????????? int ?idx?=?name.lastIndexOf( '/' ); ??
- ???????????????????????????????? //?如果以"/"結(jié)尾?是一個(gè)包 ??
- ???????????????????????????????? if ?(idx?!=?- 1 )?{ ??
- ???????????????????????????????????? //?獲取包名?把"/"替換成"." ??
- ????????????????????????????????????packageName?=?name.substring( 0 ,?idx) ??
- ????????????????????????????????????????????.replace( '/' ,? '.' ); ??
- ????????????????????????????????} ??
- ???????????????????????????????? //?如果可以迭代下去?并且是一個(gè)包 ??
- ???????????????????????????????? if ?((idx?!=?- 1 )?||?recursive)?{ ??
- ???????????????????????????????????? //?如果是一個(gè).class文件?而且不是目錄 ??
- ???????????????????????????????????? if ?(name.endsWith( ".class" ) ??
- ????????????????????????????????????????????&&?!entry.isDirectory())?{ ??
- ???????????????????????????????????????? //?去掉后面的".class"?獲取真正的類名 ??
- ????????????????????????????????????????String?className?=?name.substring( ??
- ????????????????????????????????????????????????packageName.length()?+? 1 ,?name ??
- ????????????????????????????????????????????????????????.length()?-? 6 ); ??
- ???????????????????????????????????????? try ?{ ??
- ???????????????????????????????????????????? //?添加到classes ??
- ????????????????????????????????????????????classes.add(Class ??
- ????????????????????????????????????????????????????.forName(packageName?+? '.' ??
- ????????????????????????????????????????????????????????????+?className)); ??
- ????????????????????????????????????????}? catch ?(ClassNotFoundException?e)?{ ??
- ???????????????????????????????????????????? //?log ??
- ???????????????????????????????????????????? //?.error("添加用戶自定義視圖類錯(cuò)誤?找不到此類的.class文件"); ??
- ????????????????????????????????????????????e.printStackTrace(); ??
- ????????????????????????????????????????} ??
- ????????????????????????????????????} ??
- ????????????????????????????????} ??
- ????????????????????????????} ??
- ????????????????????????} ??
- ????????????????????}? catch ?(IOException?e)?{ ??
- ???????????????????????? //?log.error("在掃描用戶定義視圖時(shí)從jar包獲取文件出錯(cuò)"); ??
- ????????????????????????e.printStackTrace(); ??
- ????????????????????} ??
- ????????????????} ??
- ????????????} ??
- ????????}? catch ?(IOException?e)?{ ??
- ????????????e.printStackTrace(); ??
- ????????} ??
- ??
- ???????? return ?classes; ??
- ????}??
/** * 從包package中獲取所有的Class * * @param pack * @return */ public static Set<Class<?>> getClasses(String pack) { // 第一個(gè)class類的集合 Set<Class<?>> classes = new LinkedHashSet<Class<?>>(); // 是否循環(huán)迭代 boolean recursive = true; // 獲取包的名字 并進(jìn)行替換 String packageName = pack; String packageDirName = packageName.replace('.', '/'); // 定義一個(gè)枚舉的集合 并進(jìn)行循環(huán)來處理這個(gè)目錄下的things Enumeration<URL> dirs; try { dirs = Thread.currentThread().getContextClassLoader().getResources( packageDirName); // 循環(huán)迭代下去 while (dirs.hasMoreElements()) { // 獲取下一個(gè)元素 URL url = dirs.nextElement(); // 得到協(xié)議的名稱 String protocol = url.getProtocol(); // 如果是以文件的形式保存在服務(wù)器上 if ("file".equals(protocol)) { System.err.println("file類型的掃描"); // 獲取包的物理路徑 String filePath = URLDecoder.decode(url.getFile(), "UTF-8"); // 以文件的方式掃描整個(gè)包下的文件 并添加到集合中 findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes); } else if ("jar".equals(protocol)) { // 如果是jar包文件 // 定義一個(gè)JarFile System.err.println("jar類型的掃描"); JarFile jar; try { // 獲取jar jar = ((JarURLConnection) url.openConnection()) .getJarFile(); // 從此jar包 得到一個(gè)枚舉類 Enumeration<JarEntry> entries = jar.entries(); // 同樣的進(jìn)行循環(huán)迭代 while (entries.hasMoreElements()) { // 獲取jar里的一個(gè)實(shí)體 可以是目錄 和一些jar包里的其他文件 如META-INF等文件 JarEntry entry = entries.nextElement(); String name = entry.getName(); // 如果是以/開頭的 if (name.charAt(0) == '/') { // 獲取后面的字符串 name = name.substring(1); } // 如果前半部分和定義的包名相同 if (name.startsWith(packageDirName)) { int idx = name.lastIndexOf('/'); // 如果以"/"結(jié)尾 是一個(gè)包 if (idx != -1) { // 獲取包名 把"/"替換成"." packageName = name.substring(0, idx) .replace('/', '.'); } // 如果可以迭代下去 并且是一個(gè)包 if ((idx != -1) || recursive) { // 如果是一個(gè).class文件 而且不是目錄 if (name.endsWith(".class") && !entry.isDirectory()) { // 去掉后面的".class" 獲取真正的類名 String className = name.substring( packageName.length() + 1, name .length() - 6); try { // 添加到classes classes.add(Class .forName(packageName + '.' + className)); } catch (ClassNotFoundException e) { // log // .error("添加用戶自定義視圖類錯(cuò)誤 找不到此類的.class文件"); e.printStackTrace(); } } } } } } catch (IOException e) { // log.error("在掃描用戶定義視圖時(shí)從jar包獲取文件出錯(cuò)"); e.printStackTrace(); } } } } catch (IOException e) { e.printStackTrace(); } return classes; }?
?
- /** ?
- ?????*?以文件的形式來獲取包下的所有Class ?
- ?????*? ?
- ?????*?@param?packageName ?
- ?????*?@param?packagePath ?
- ?????*?@param?recursive ?
- ?????*?@param?classes ?
- ?????*/ ??
- ???? public ? static ? void ?findAndAddClassesInPackageByFile(String?packageName, ??
- ????????????String?packagePath,? final ? boolean ?recursive,?Set<Class<?>>?classes)?{ ??
- ???????? //?獲取此包的目錄?建立一個(gè)File ??
- ????????File?dir?=? new ?File(packagePath); ??
- ???????? //?如果不存在或者?也不是目錄就直接返回 ??
- ???????? if ?(!dir.exists()?||?!dir.isDirectory())?{ ??
- ???????????? //?log.warn("用戶定義包名?"?+?packageName?+?"?下沒有任何文件"); ??
- ???????????? return ; ??
- ????????} ??
- ???????? //?如果存在?就獲取包下的所有文件?包括目錄 ??
- ????????File[]?dirfiles?=?dir.listFiles( new ?FileFilter()?{ ??
- ???????????? //?自定義過濾規(guī)則?如果可以循環(huán)(包含子目錄)?或則是以.class結(jié)尾的文件(編譯好的java類文件) ??
- ???????????? public ? boolean ?accept(File?file)?{ ??
- ???????????????? return ?(recursive?&&?file.isDirectory()) ??
- ????????????????????????||?(file.getName().endsWith( ".class" )); ??
- ????????????} ??
- ????????}); ??
- ???????? //?循環(huán)所有文件 ??
- ???????? for ?(File?file?:?dirfiles)?{ ??
- ???????????? //?如果是目錄?則繼續(xù)掃描 ??
- ???????????? if ?(file.isDirectory())?{ ??
- ????????????????findAndAddClassesInPackageByFile(packageName?+? "." ??
- ????????????????????????+?file.getName(),?file.getAbsolutePath(),?recursive, ??
- ????????????????????????classes); ??
- ????????????}? else ?{ ??
- ???????????????? //?如果是java類文件?去掉后面的.class?只留下類名 ??
- ????????????????String?className?=?file.getName().substring( 0 , ??
- ????????????????????????file.getName().length()?-? 6 ); ??
- ???????????????? try ?{ ??
- ???????????????????? //?添加到集合中去 ??
- ???????????????????? //classes.add(Class.forName(packageName?+?'.'?+?className)); ??
- ????????????????????????????????????????? //經(jīng)過回復(fù)同學(xué)的提醒,這里用forName有一些不好,會觸發(fā)static方法,沒有使用classLoader的load干凈 ??
- ????????????????????????????????????????classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName?+? '.' ?+?className));?? ??
- ????????????????????????????????}? catch ?(ClassNotFoundException?e)?{ ??
- ???????????????????? //?log.error("添加用戶自定義視圖類錯(cuò)誤?找不到此類的.class文件"); ??
- ????????????????????e.printStackTrace(); ??
- ????????????????} ??
- ????????????} ??
- ????????} ??
- ????}??
/** * 以文件的形式來獲取包下的所有Class * * @param packageName * @param packagePath * @param recursive * @param classes */ public static void findAndAddClassesInPackageByFile(String packageName, String packagePath, final boolean recursive, Set<Class<?>> classes) { // 獲取此包的目錄 建立一個(gè)File File dir = new File(packagePath); // 如果不存在或者 也不是目錄就直接返回 if (!dir.exists() || !dir.isDirectory()) { // log.warn("用戶定義包名 " + packageName + " 下沒有任何文件"); return; } // 如果存在 就獲取包下的所有文件 包括目錄 File[] dirfiles = dir.listFiles(new FileFilter() { // 自定義過濾規(guī)則 如果可以循環(huán)(包含子目錄) 或則是以.class結(jié)尾的文件(編譯好的java類文件) public boolean accept(File file) { return (recursive && file.isDirectory()) || (file.getName().endsWith(".class")); } }); // 循環(huán)所有文件 for (File file : dirfiles) { // 如果是目錄 則繼續(xù)掃描 if (file.isDirectory()) { findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes); } else { // 如果是java類文件 去掉后面的.class 只留下類名 String className = file.getName().substring(0, file.getName().length() - 6); try { // 添加到集合中去 //classes.add(Class.forName(packageName + '.' + className)); //經(jīng)過回復(fù)同學(xué)的提醒,這里用forName有一些不好,會觸發(fā)static方法,沒有使用classLoader的load干凈 classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className)); ?} catch (ClassNotFoundException e) { // log.error("添加用戶自定義視圖類錯(cuò)誤 找不到此類的.class文件"); e.printStackTrace(); } } } }?
?
??????? 自己直接拿過來用了,可以掃描package對應(yīng)的子package,不過是對當(dāng)前classLoad下的所有jar進(jìn)行掃描的。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
