电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

詳解Java 包掃描實現和應用(Jar篇)

瀏覽:2日期:2022-08-28 10:46:19

如果你曾經使用過 Spring, 那你已經配過 包掃描路徑吧,那包掃描是怎么實現的呢?讓我們自己寫個包掃描

上篇文章中介紹了使用 File 遍歷的方式去進行包掃描,這篇主要補充一下jar包的掃描方式,在我們的項目中一般都會去依賴一些其他jar 包,

比如添加 guava 依賴

<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>28.2-jre</version></dependency>

我們再次運行上次的測試用例

@Testpublic void testGetPackageAllClasses() throws IOException, ClassNotFoundException { ClassScanner scanner = new ClassScanner('com.google.common.cache', true, null, null); Set<Class<?>> packageAllClasses = scanner.doScanAllClasses(); packageAllClasses.forEach(it -> { System.out.println(it.getName()); });}

什么都沒有輸出

依賴的 Jar

基于Java 的反射機制,我們很容易根據 class 去創建一個實例對象,但如果我們根本不知道某個包下有多少對象時,我們應該怎么做呢?

在使用Spring框架時,會根據包掃描路徑來找到所有的 class, 并將其實例化后存入容器中。

在我們的項目中也會遇到這樣的場景,比如某個包為 org.example.plugins, 這個里面放著所有的插件,為了不每次增減插件都要手動修改代碼,我們可能會想到用掃描的方式去動態獲知 org.example.plugins 到底有多少 class, 當然應用場景很有很多

思路

既然知道是采用了 jar , 那我們使用遍歷 jar 的方式去處理一下

JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile();// 遍歷jar包中的元素Enumeration<JarEntry> entries = jar.entries();while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); String name = entry.getName();}

這里獲取的name 格式為 com/google/common/cache/Cache.class 是不是和上篇的文件路徑很像呀, 這里可以通過對 name 進行操作獲取包名和 class

// 獲取包名String jarPackageName = name.substring(0, name.lastIndexOf(’/’)).replace('/', '.');// 獲取 class 路徑, 這樣就能通過類加載進行加載了String className = name.replace(’/’, ’.’);className = className.substring(0, className.length() - 6);

完整代碼

private void doScanPackageClassesByJar(String basePackage, URL url, Set<Class<?>> classes) throws IOException, ClassNotFoundException { // 包名 String packageName = basePackage; // 獲取文件路徑 String basePackageFilePath = packageName.replace(’.’, ’/’); // 轉為jar包 JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile(); // 遍歷jar包中的元素 Enumeration<JarEntry> entries = jar.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); String name = entry.getName(); // 如果路徑不一致,或者是目錄,則繼續 if (!name.startsWith(basePackageFilePath) || entry.isDirectory()) { continue; } // 判斷是否遞歸搜索子包 if (!recursive && name.lastIndexOf(’/’) != basePackageFilePath.length()) { continue; } if (packagePredicate != null) { String jarPackageName = name.substring(0, name.lastIndexOf(’/’)).replace('/', '.'); if (!packagePredicate.test(jarPackageName)) { continue; } } // 判定是否符合過濾條件 String className = name.replace(’/’, ’.’); className = className.substring(0, className.length() - 6); // 用當前線程的類加載器加載類 Class<?> loadClass = Thread.currentThread().getContextClassLoader().loadClass(className); if (classPredicate == null || classPredicate.test(loadClass)) { classes.add(loadClass); } }}

在結合上篇中 File 掃描方式就是完成的代碼了

整合后代碼

package org.example;import java.io.File;import java.io.FileFilter;import java.io.IOException;import java.net.JarURLConnection;import java.net.URL;import java.net.URLDecoder;import java.util.Enumeration;import java.util.LinkedHashSet;import java.util.Set;import java.util.function.Predicate;import java.util.jar.JarEntry;import java.util.jar.JarFile;/** * class 掃描器 * * @author zhangyunan */public class ClassScanner { private final String basePackage; private final boolean recursive; private final Predicate<String> packagePredicate; private final Predicate<Class> classPredicate; /** * Instantiates a new Class scanner. * * @param basePackage the base package * @param recursive 是否遞歸掃描 * @param packagePredicate the package predicate * @param classPredicate the class predicate */ public ClassScanner(String basePackage, boolean recursive, Predicate<String> packagePredicate, Predicate<Class> classPredicate) { this.basePackage = basePackage; this.recursive = recursive; this.packagePredicate = packagePredicate; this.classPredicate = classPredicate; } /** * Do scan all classes set. * * @return the set * @throws IOException the io exception * @throws ClassNotFoundException the class not found exception */ public Set<Class<?>> doScanAllClasses() throws IOException, ClassNotFoundException { Set<Class<?>> classes = new LinkedHashSet<Class<?>>(); String packageName = basePackage; // 如果最后一個字符是“.”,則去掉 if (packageName.endsWith('.')) { packageName = packageName.substring(0, packageName.lastIndexOf(’.’)); } // 將包名中的“.”換成系統文件夾的“/” String basePackageFilePath = packageName.replace(’.’, ’/’); Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(basePackageFilePath); while (resources.hasMoreElements()) { URL resource = resources.nextElement(); String protocol = resource.getProtocol(); if ('file'.equals(protocol)) { String filePath = URLDecoder.decode(resource.getFile(), 'UTF-8'); // 掃描文件夾中的包和類 doScanPackageClassesByFile(classes, packageName, filePath); } else if ('jar'.equals(protocol)) { doScanPackageClassesByJar(packageName, resource, classes); } } return classes; } private void doScanPackageClassesByJar(String basePackage, URL url, Set<Class<?>> classes) throws IOException, ClassNotFoundException { // 包名 String packageName = basePackage; // 獲取文件路徑 String basePackageFilePath = packageName.replace(’.’, ’/’); // 轉為jar包 JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile(); // 遍歷jar包中的元素 Enumeration<JarEntry> entries = jar.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); String name = entry.getName(); // 如果路徑不一致,或者是目錄,則繼續 if (!name.startsWith(basePackageFilePath) || entry.isDirectory()) { continue; } // 判斷是否遞歸搜索子包 if (!recursive && name.lastIndexOf(’/’) != basePackageFilePath.length()) { continue; } if (packagePredicate != null) { String jarPackageName = name.substring(0, name.lastIndexOf(’/’)).replace('/', '.'); if (!packagePredicate.test(jarPackageName)) { continue; } } // 判定是否符合過濾條件 String className = name.replace(’/’, ’.’); className = className.substring(0, className.length() - 6); // 用當前線程的類加載器加載類 Class<?> loadClass = Thread.currentThread().getContextClassLoader().loadClass(className); if (classPredicate == null || classPredicate.test(loadClass)) { classes.add(loadClass); } } } /** * 在文件夾中掃描包和類 */ private void doScanPackageClassesByFile(Set<Class<?>> classes, String packageName, String packagePath) throws ClassNotFoundException { // 轉為文件 File dir = new File(packagePath); if (!dir.exists() || !dir.isDirectory()) { return; } // 列出文件,進行過濾 // 自定義文件過濾規則 File[] dirFiles = dir.listFiles((FileFilter) file -> { String filename = file.getName(); if (file.isDirectory()) { if (!recursive) { return false; } if (packagePredicate != null) { return packagePredicate.test(packageName + '.' + filename); } return true; } return filename.endsWith('.class'); }); if (null == dirFiles) { return; } for (File file : dirFiles) { if (file.isDirectory()) { // 如果是目錄,則遞歸 doScanPackageClassesByFile(classes, packageName + '.' + file.getName(), file.getAbsolutePath()); } else { // 用當前類加載器加載 去除 fileName 的 .class 6 位 String className = file.getName().substring(0, file.getName().length() - 6); Class<?> loadClass = Thread.currentThread().getContextClassLoader().loadClass(packageName + ’.’ + className); if (classPredicate == null || classPredicate.test(loadClass)) { classes.add(loadClass); } } } }}

到此這篇關于詳解Java 包掃描實現和應用(Jar篇)的文章就介紹到這了,更多相關Java 包掃描實現和應用內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Java
相關文章:
主站蜘蛛池模板: 丹佛斯变频器-丹佛斯压力开关-变送器-广州市风华机电设备有限公司 | 喷砂机厂家_自动除锈抛丸机价格-成都泰盛吉自动化喷砂设备 | 北京中创汇安科贸有限公司| 全自动变压器变比组别测试仪-手持式直流电阻测试仪-上海来扬电气 | 考试试题_试卷及答案_诗词单词成语 - 优易学 | 苏州伊诺尔拆除公司_专业酒店厂房拆除_商场学校拆除_办公楼房屋拆除_家工装拆除拆旧 | 东亚液氮罐-液氮生物容器-乐山市东亚机电工贸有限公司 | 好看的韩国漫画_韩漫在线免费阅读-汗汗漫画 | 电缆接头_防水接头_电缆防水接头_防水电缆接头_上海闵彬 | 威实软件_软件定制开发_OA_OA办公系统_OA系统_办公自动化软件 | 液压扳手-高品质液压扳手供应商 - 液压扳手, 液压扳手供应商, 德国进口液压拉马 | 专业深孔加工_东莞深孔钻加工_东莞深孔钻_东莞深孔加工_模具深孔钻加工厂-东莞市超耀实业有限公司 | 客服外包专业服务商_客服外包中心_网萌科技 | 户外环保不锈钢垃圾桶_标识标牌制作_园林公园椅厂家_花箱定制-北京汇众环艺 | 塑料薄膜_PP薄膜_聚乙烯薄膜-常州市鑫美新材料包装厂 | 标准光源箱|对色灯箱|色差仪|光泽度仪|涂层测厚仪_HRC大品牌生产厂家 | 耐高温风管_耐高温软管_食品级软管_吸尘管_钢丝软管_卫生级软管_塑料波纹管-东莞市鑫翔宇软管有限公司 | 广东高华家具-公寓床|学生宿舍双层铁床厂家【质保十年】 | 辐射仪|辐射检测仪|辐射巡测仪|个人剂量报警仪|表面污染检测仪|辐射报警仪|辐射防护网 | 大通天成企业资质代办_承装修试电力设施许可证_增值电信业务经营许可证_无人机运营合格证_广播电视节目制作许可证 | 金蝶帐无忧|云代账软件|智能财税软件|会计代账公司专用软件 | ICP备案查询_APP备案查询_小程序备案查询 - 备案巴巴 | 恒温恒湿试验箱_高低温试验箱_恒温恒湿箱-东莞市高天试验设备有限公司 | 刮板输送机,粉尘加湿搅拌机,螺旋输送机,布袋除尘器 | 酒店厨房设计_中央厨房设计_北京商用厨房设计公司-奇能商厨 | 包装盒厂家_纸盒印刷_礼品盒定制-济南恒印包装有限公司 | 气动绞车,山东气动绞车,气动绞车厂家-烟台博海石油机械有限公司 气动隔膜泵厂家-温州永嘉定远泵阀有限公司 | 机床主轴维修|刀塔维修|C轴维修-常州翔高精密机械有限公司 | 科箭WMS仓库管理软件-TMS物流管理系统-科箭SaaS云服务 | 电缆故障测试仪_电缆故障定位仪_探测仪_检测仪器_陕西意联电气厂家 | 光泽度计_测量显微镜_苏州压力仪_苏州扭力板手维修-苏州日升精密仪器有限公司 | 定制异形重型钢格栅板/钢格板_定做踏步板/排水沟盖板_钢格栅板批发厂家-河北圣墨金属制品有限公司 | 非标压力容器_碳钢储罐_不锈钢_搪玻璃反应釜厂家-山东首丰智能环保装备有限公司 | AGV叉车|无人叉车|AGV智能叉车|AGV搬运车-江西丹巴赫机器人股份有限公司 | 地图标注-手机导航电子地图如何标注-房地产商场地图标记【DiTuBiaoZhu.net】 | 密封圈_泛塞封_格莱圈-[东莞市国昊密封圈科技有限公司]专注密封圈定制生产厂家 | 东莞螺丝|东莞螺丝厂|东莞不锈钢螺丝|东莞组合螺丝|东莞精密螺丝厂家-东莞利浩五金专业紧固件厂家 | 轻型地埋电缆故障测试仪,频响法绕组变形测试仪,静荷式卧式拉力试验机-扬州苏电 | 【电子厂招聘_普工招工网_工厂招聘信息平台】-工立方打工网 | 小型UV打印机-UV平板打印机-大型uv打印机-UV打印机源头厂家 |松普集团 | 登车桥动力单元-非标液压泵站-非标液压系统-深圳市三好科技有限公司 |