Java扫描classpath指定包路径下所有class

在写框架时 经常需要扫描classpath指定包路径下带有某个Annotation的类,自己整理了一下 封装成一个工具类了,供大家参考。

源代码
ClassPathResourceScanner.java 如下:

package com.bytebeats.jupiter.ioc;

import com.bytebeats.jupiter.util.ClassHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.regex.Pattern;

/**
* ${DESCRIPTION}
*
* @author Ricky Fung
* @create 2016-12-11 16:02
*/
public class ClassPathCandidateComponentScanner {
private final Logger logger = LoggerFactory.getLogger(getClass());

public static final String CLASS_SUFFIX = ".class";

private static final Pattern INNER_PATTERN = java.util.regex.Pattern.compile("\\$(\\d+).", java.util.regex.Pattern.CASE_INSENSITIVE);

public Set<Class<?>> findCandidateComponents(String packageName) throws IOException {
if (packageName.endsWith(".")) {
packageName = packageName.substring(0, packageName.length()-1);
}
Map<String, String> classMap = new HashMap<>(32);
String path = packageName.replace(".", "/");
Enumeration<URL> urls = findAllClassPathResources(path);
while (urls!=null && urls.hasMoreElements()) {
URL url = urls.nextElement();
String protocol = url.getProtocol();
if ("file".equals(protocol)) {
String file = URLDecoder.decode(url.getFile(), "UTF-8");
File dir = new File(file);
if(dir.isDirectory()){
parseClassFile(dir, packageName, classMap);
}else {
throw new IllegalArgumentException("file must be directory");
}
} else if ("jar".equals(protocol)) {
parseJarFile(url, classMap);
}
}

Set<Class<?>> set = new HashSet<>(classMap.size());
for(String key : classMap.keySet()){
String className = classMap.get(key);
try {
set.add(ClassHelper.forName(className));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return set;
}

protected void parseClassFile(File dir, String packageName, Map<String, String> classMap){
if(dir.isDirectory()){
File[] files = dir.listFiles();
for (File file : files) {
parseClassFile(file, packageName, classMap);
}
} else if(dir.getName().endsWith(CLASS_SUFFIX)) {
String name = dir.getPath();
name = name.substring(name.indexOf("classes")+8).replace("\\", ".");
System.out.println("file:"+dir+"\t class:"+name);
addToClassMap(name, classMap);
}
}

protected void parseJarFile(URL url, Map<String, String> classMap) throws IOException {
JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile();
Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (entry.isDirectory()) {
continue;
}
String name = entry.getName();
if(name.endsWith(CLASS_SUFFIX)){
addToClassMap(name.replace("/", "."), classMap);
}
}
}

private boolean addToClassMap(String name, Map<String, String> classMap){

if(INNER_PATTERN.matcher(name).find()){ //过滤掉匿名内部类
System.out.println("anonymous inner class:"+name);
return false;
}
System.out.println("class:"+name);
if(name.indexOf("$")>0){ //内部类
System.out.println("inner class:"+name);
}
if(!classMap.containsKey(name)){
classMap.put(name, name.substring(0, name.length()-6)); //去掉.class
}
return true;
}

protected Enumeration<URL> findAllClassPathResources(String path) throws IOException {
if(path.startsWith("/")){
path = path.substring(1);
}
Enumeration<URL> urls = ClassHelper.getClassLoader().getResources(path);

return urls;
}

}
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
使用方法
ClassPathCandidateComponentScanner scanner = new ClassPathCandidateComponentScanner();
//要扫描的包名
String packageName = "com.bytebeats";
//获取该包下所有的类名称
Set<Class<?>> set = scanner.findCandidateComponents(packageName);
System.out.println(set.size());
for (Class<?> cls : set){
System.out.println(cls.getName());
}
1
2
3
4
5
6
7
8
9

这方面已经有一些不错的开源项目,例如:
reflections:https://github.com/ronmamo/reflections
Scannotation:http://scannotation.sourceforge.net/
---------------------
作者:Ricky_Fung
来源:CSDN
原文:https://blog.csdn.net/top_code/article/details/53574523
版权声明:本文为博主原创文章,转载请附上博文链接!

原文地址:https://www.cnblogs.com/hfultrastrong/p/9810202.html

时间: 2024-10-01 13:27:18

Java扫描classpath指定包路径下所有class的相关文章

Java扫描指定文件路径下的文件并且递归扫描其子目录下的所有文件

本文主要实现了扫描指定文件路径下的文件,递归扫描其子目录下的所有文件信息,示例文件为: 要求将后缀为.dat的文件夹信息也写入到数据库中,然后将.chk文件解析,将文件中对应的内容读出来写入到数据库,对应类为ChkFileParseFactroy,本文文件发现代码为: 1 package com.src.service.impl; 2 3 import java.io.File; 4 import java.net.InetAddress; 5 import java.net.NetworkIn

java批量修改指定文件夹下所有后缀名的文件为另外后缀名的代码

原文:java批量修改指定文件夹下所有后缀名的文件为另外后缀名的代码 源代码下载地址:http://www.zuidaima.com/share/1550463660264448.htm 今天有个需求,想把某个文件夹下所有后缀名为jsp的更改为ftl,本来想用bat实现对bat的高级语法也不太了解,后来发现还需要递归遍历所有的子文件夹,所以用java实现了一个功能一样的代码,有需要的牛人可以下载修改为自己想要的. 这样可以兼容windows和linux. package com.zuidaima

java.io.tmpdir指定的路径在哪?

Java.io.tmpdir介绍 System.getproperty("java.io.tmpdir")是获取操作系统缓存的临时目录,不同操作系统的缓存临时目录不一样, 在Windows的缓存目录为:C:\Users\登录用户~1\AppData\Local\Temp\ Linux:/tmp System.getProperty(""),可以操作一下参数: java.version Java运行时环境版本 java.vendor Java运行时环境供应商 java

Spring根据包名获取包路径下的所有类

参考mybatis MapperScannerConfigurer.java 最终找到 Spring的一个类  ClassPathBeanDefinitionScanner.java 参考ClassPathBeanDefinitionScanner 和它的父类 ClassPathScanningCandidateComponentProvider,将一些代码进行抽取,得到如下工具类. import org.apache.commons.lang3.ArrayUtils; import org.s

Java递归搜索指定文件夹下的匹配文件

import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Queue; /** * @author tiwson 2010-06-02 * */ public class FileSearcher { /** * 递归查找文件 * @param baseDirName 查找的文件夹路径 * @param targetFileName 需要查找的文件名 * @param file

JAVA调用R脚本 windwos路径下

RConnection c = new RConnection();// REXP x = c.eval("source('D:\\\\jiaoben\\\\RJava_test.R',encoding = \"UTF-8\")"); REXP x = c.eval("source('D:\\\\jiaoben\\\\Rjava_testx6.R',encoding = \"UTF-8\")");// REXP eval =

SqlSever基础 使用脚本创建数据库及日志文件到指定的路径下

1 2 code 1 create database helloworld 2 3 --设置mdf文件的属性 4 on primary 5 ( 6 name = 'aHelloWorldLogic', --mdf文件的逻辑名字(不是文件名字) 7 filename = 'C:\Users\Administrator\Desktop\aHelloWorld.mdf', --mdf文件的存储路径及其文件名字 8 size=5mb,--初始大小为5兆 9 filegrowth=10%,--文件每次增长

javac\java 含有包路径的类

近两天因为刚入职,属于熟悉环境的阶段,研究了下算法(第四版),当不使用IDE工具直接使用终端进行javac 编译带有包的类,然后使用java 会出现如下错误提示: 使用谷歌搜索了很久,终于找到解决的办法,作记录一下,免得到时候会忘 因为该问题的出现时因为BinarySearch.java类中存在包路径,该文件我是使用eclipse,放到workspace中的. package com.sort; public class BinarySearch { public static int rank

Delphi - 本地路径的创建、清空本地指定文件夹下的文件

本地路径的创建 在做下载操作时,我们一般先把文件下载到本地指定的路径下,然后再做其他使用. 为了防止程序出现异常,我们通常需要先判断本地是否存在指定的路径. 以C盘Tmp文件夹为例,我们可以这样做,代码如下: 1 if not DirectoryExists('C:\Tmp') then 2 if not CreateDir('C:\Tmp') then 3 raise 4 Exception.Create('Opps, Create New Dir Failed!'); 清空本地指定文件夹下的