java獲取包下被指定注解的類過程解析
方案一: 采用reflections 框架(此框架依賴com.google.guava)
1、reflections框架地址:https://github.com/ronmamo/reflections
2、項(xiàng)目依賴
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.11</version>
</dependency>
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId>
<version>21.0</version>
</dependency>
3、實(shí)現(xiàn)代碼
//入?yún)?要掃描的包名
Reflections f = new Reflections("com.ggband.netty.execute.command");
//入?yún)?目標(biāo)注解類
Set<Class<?>> set = f.getTypesAnnotatedWith(Cmd.class);
方案二: 采用ClassLoader掃描
1、實(shí)現(xiàn)代碼
package com.ggband.netty;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class Scanner {
/**
* 從包package中獲取所有的Class
*
* @param packageName
* @return
*/
public Set<Class<?>> getClasses(String packageName) throws Exception {
// 第一個(gè)class類的集合
//List<Class<?>> classes = new ArrayList<Class<?>>();
Set<Class<?>> classes = new HashSet<>();
// 是否循環(huán)迭代
boolean recursive = true;
// 獲取包的名字 并進(jìn)行替換
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)) {
// 獲取包的物理路徑
String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
// 以文件的方式掃描整個(gè)包下的文件 并添加到集合中
addClass(classes, filePath, packageName);
} else if ("jar".equals(protocol)) {
// 如果是jar包文件
// 定義一個(gè)JarFile
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) {
e.printStackTrace();
}
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return classes;
}
public void addClass(Set<Class<?>> classes, String filePath, String packageName) throws Exception {
File[] files = new File(filePath).listFiles(file -> (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory());
assert files != null;
for (File file : files) {
String fileName = file.getName();
if (file.isFile()) {
String classsName = fileName.substring(0, fileName.lastIndexOf("."));
if (!packageName.isEmpty()) {
classsName = packageName + "." + classsName;
}
doAddClass(classes, classsName);
}
}
}
public void doAddClass(Set<Class<?>> classes, final String classsName) throws Exception {
ClassLoader classLoader = new ClassLoader() {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
return super.loadClass(name);
}
};
classes.add(classLoader.loadClass(classsName));
}
public <A extends Annotation> Set<Class<?>> getAnnotationClasses(String packageName, Class<A> annotationClass) throws Exception {
//找用了annotationClass注解的類
Set<Class<?>> controllers = new HashSet<>();
Set<Class<?>> clsList = getClasses(packageName);
if (clsList != null && clsList.size() > 0) {
for (Class<?> cls : clsList) {
if (cls.getAnnotation(annotationClass) != null) {
controllers.add(cls);
}
}
}
return controllers;
}
}
2、使用:
Set<Class<?>> set = new Scanner().getAnnotationClasses("com.ggband.netty.execute.command", Cmd.class);
擴(kuò)充:現(xiàn)在就可以實(shí)現(xiàn)自己的業(yè)務(wù)了,比如 掃描com.ggband.netty.execute.command包下被Cmd注解的類 得到Cmd注解value和被注解類的實(shí)例
Map<String, Command> beanContainer = new HashMap<>();
try {
//@1 采用reflections 框架(此框架依賴com.google.guava)
// Reflections f = new Reflections("com.ggband.netty.execute.command");
// Set<Class<?>> set = f.getTypesAnnotatedWith(Cmd.class);
//@2 采用ClassLoader掃描
Set<Class<?>> set = new Scanner().getAnnotationClasses("com.ggband.netty.execute.command", Cmd.class);
for (Class<?> c : set) {
Object bean = c.newInstance();
Cmd annotation = c.getAnnotation(Cmd.class);
beanContainer.put(Arrays.toString(annotation.value()), (Command) bean);
}
} catch (Exception e) {
e.printStackTrace();
}
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
兩種Eclipse部署動(dòng)態(tài)web項(xiàng)目方法
這篇文章主要介紹了兩種Eclipse部署動(dòng)態(tài)web項(xiàng)目方法,需要的朋友可以參考下2015-11-11
基于Java8 Stream API實(shí)現(xiàn)數(shù)據(jù)抽取收集
這篇文章主要介紹了基于Java8 Stream API實(shí)現(xiàn)數(shù)據(jù)抽取收集,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03
Spring Boot 自定義數(shù)據(jù)源DruidDataSource代碼
這篇文章主要介紹了Spring Boot 自定義數(shù)據(jù)源DruidDataSource代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10
spring boot 項(xiàng)目利用Jenkins實(shí)現(xiàn)自動(dòng)化部署的教程詳解
這篇文章主要介紹了spring boot 項(xiàng)目利用Jenkins實(shí)現(xiàn)自動(dòng)化部署的方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-07-07
Eclipse+Java+Swing實(shí)現(xiàn)斗地主游戲(代碼)
這篇文章主要介紹了Eclipse+Java+Swing實(shí)現(xiàn)斗地主游戲并附上詳細(xì)的代碼實(shí)現(xiàn),正在學(xué)習(xí)的你可以當(dāng)小練習(xí)練練,希望對(duì)你有所幫助2022-01-01

