激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 詳解Java 包掃描實現和應用(Jar篇)

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

2020-07-26 00:05zyndev Java教程

這篇文章主要介紹了詳解Java 包掃描實現和應用(Jar篇),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

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

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

比如添加 guava 依賴

?
1
2
3
4
5
<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>28.2-jre</version>
</dependency>

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

?
1
2
3
4
5
6
7
8
@Test
public 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 的方式去處理一下

?
1
2
3
4
5
6
7
8
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

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

完整代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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 掃描方式就是完成的代碼了

整合后代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
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 包掃描實現和應用內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://www.cnblogs.com/zyndev/p/13374811.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 日韩av电影在线免费观看 | 爱性久久久久久久 | 欧美顶级毛片在线播放小说 | 狠狠操人人干 | 免费观看视频网站 | 国产日韩线路一线路二 | 一分钟免费观看完整版电影 | 免费a级毛片大学生免费观看 | 国产日产精品一区二区三区四区 | 久久久三级免费电影 | 欧美大荫蒂xxx | 国产免费v片 | chinese xvideos gay| 13一14毛片免费看 | www噜噜偷拍在线视频 | 国色天香综合网 | 日本娇小18xxxⅹhd | 日韩精品a在线观看 | 日韩精品dvd| 久久久久91视频 | 国产精品午夜未成人免费观看 | 中文字幕视频在线播放 | 五月天堂av91久久久 | 国产1区2区3区中文字幕 | 草逼一区 | 国产一及毛片 | 国产免费视频在线 | 一区二区久久电影 | 高清国产午夜精品久久久久久 | 精品99在线视频 | 欧美成人免费一级 | 99视频有精品视频高清 | 亚洲第一色片 | 精品一区二区在线播放 | 毛片国产 | 欧美特黄三级成人 | 1级黄色毛片 | 在线成人一区二区 | 亚洲一区 国产精品 | 亚洲综合精品 | 91精品国|