一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

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

服務(wù)器之家 - 編程語言 - Java教程 - 詳解Java 包掃描實現(xiàn)和應(yīng)用(Jar篇)

詳解Java 包掃描實現(xiàn)和應(yīng)用(Jar篇)

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

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

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

上篇文章中介紹了使用 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 的反射機制,我們很容易根據(jù) class 去創(chuàng)建一個實例對象,但如果我們根本不知道某個包下有多少對象時,我們應(yīng)該怎么做呢?

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

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

思路

既然知道是采用了 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('.', '/');
 // 轉(zhuǎn)為jar包
 JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile();
 // 遍歷jar包中的元素
 Enumeration<JarEntry> entries = jar.entries();
 while (entries.hasMoreElements()) {
  JarEntry entry = entries.nextElement();
  String name = entry.getName();
  // 如果路徑不一致,或者是目錄,則繼續(xù)
  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);
  // 用當(dāng)前線程的類加載器加載類
  Class<?> loadClass = Thread.currentThread().getContextClassLoader().loadClass(className);
  if (classPredicate == null || classPredicate.test(loadClass)) {
   classes.add(loadClass);
  }
 
 }
}

在結(jié)合上篇中 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('.'));
  }
 
  // 將包名中的“.”換成系統(tǒng)文件夾的“/”
  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('.', '/');
  // 轉(zhuǎn)為jar包
  JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile();
  // 遍歷jar包中的元素
  Enumeration<JarEntry> entries = jar.entries();
  while (entries.hasMoreElements()) {
   JarEntry entry = entries.nextElement();
   String name = entry.getName();
   // 如果路徑不一致,或者是目錄,則繼續(xù)
   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);
   // 用當(dāng)前線程的類加載器加載類
   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 {
  // 轉(zhuǎn)為文件
  File dir = new File(packagePath);
  if (!dir.exists() || !dir.isDirectory()) {
   return;
  }
  // 列出文件,進行過濾
  // 自定義文件過濾規(guī)則
  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 {
    // 用當(dāng)前類加載器加載 去除 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);
    }
   }
  }
 }
}

到此這篇關(guān)于詳解Java 包掃描實現(xiàn)和應(yīng)用(Jar篇)的文章就介紹到這了,更多相關(guān)Java 包掃描實現(xiàn)和應(yīng)用內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!

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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 青青草原伊人网 | 色中色破解版 | 免费在线观看中文字幕 | 草草视频在线观看最新 | 大学生宿舍飞机 free | 欧美三级做爰全过程 | 男人叼女人的痛爽视频免费 | 国产成人性色视频 | 欧美在线观看视频一区 | 二区三区不卡不卡视频 | 236z最新伦理 | 深夜视频免费看 | 亚洲国产成人精品无码区99 | 久久婷婷五月综合色丁香花 | 99精品免费在线 | 国产精品高清视亚洲一区二区 | 99国产高清久久久久久网站 | 亚洲国产精久久久久久久 | 亚洲mv国产精品mv日本mv | 极端 成熟 性别 视频 | 国产精品成人 | 视频免费视频观看网站 | 男人躁女人过程 | 欧美帅老头oldmangay | 欧美视频在线一区二区三区 | 亚洲欧美久久婷婷爱综合一区天堂 | 无遮18禁在线永久免费观看挡 | 俄罗斯bbbbbbbbb大片 | 亚洲酒色1314狠狠做 | 色久久一个亚洲综合网 | 国产美女做爰免费视频软件 | 99精品视频免费观看 | 亚裔maricahase和黑人 | 小小水蜜桃视频高清在线观看免费 | 亚洲精品国偷拍自产在线观看蜜臀 | 亚洲成人国产精品 | 亚洲国产精品一区二区首页 | 色漫在线观看 | 国产欧美日韩精品高清二区综合区 | 久久视频这里只精品99热在线观看 | 四虎影视网址 |