您现在的位置是:首页 > 技术人生 > 后端技术后端技术
java扫描包下所有类的完整路径
高晓波2020-08-18【后端技术】人已围观
简介最近在完善微信公众号返利机器人订单轮训、跟踪。业务逻辑是定时任务调用淘客API,按一定条件查询某时间段内的返利订单。定时任务框架用的quartz,原先定时任务写死在代码中,此次优化将定时任务做成可视化配置,更加灵活、通用。
最近在完善微信公众号返利机器人订单轮训、跟踪。
业务逻辑是定时任务调用淘客API,按一定条件查询某时间段内的返利订单。定时任务框架用的quartz,原先定时任务写死在代码中,此次优化将定时任务做成可视化配置,更加灵活、通用。
今天暂不讨论、总结quartz定时任务可视化配置,有需要的同学可以参考《Springboot集成quartz定时任务可视化配置》。
用过quartz的应该知道,所有的定时任务都是直接或间接的继承Job类,我们把所有的job类放在同一个包下,做成可视化需要解决的就是扫描此包,获取包下所有的job类。
直接贴上扫描包下所有类代码
业务逻辑是定时任务调用淘客API,按一定条件查询某时间段内的返利订单。定时任务框架用的quartz,原先定时任务写死在代码中,此次优化将定时任务做成可视化配置,更加灵活、通用。
今天暂不讨论、总结quartz定时任务可视化配置,有需要的同学可以参考《Springboot集成quartz定时任务可视化配置》。
用过quartz的应该知道,所有的定时任务都是直接或间接的继承Job类,我们把所有的job类放在同一个包下,做成可视化需要解决的就是扫描此包,获取包下所有的job类。
直接贴上扫描包下所有类代码
package com.gaoxiaobo.download.component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
/**
* @Auther: gaoxiaobo
* @Date: 2020/8/8 21:17
* @Description:
*/
public class ClasspathPackageScanner {
private static Logger logger = LoggerFactory.getLogger(ClasspathPackageScanner.class);
private static ClassLoader cl = ClasspathPackageScanner.class.getClassLoader();
/**
*获取指定包下的所有字节码文件的全类名
*/
public static List<String> getFullyQualifiedClassNameList(String basePackage) throws Exception {
return doScan(basePackage, new ArrayList<>());
}
private static List<String> scanJar(String basePackage)throws Exception{
List<String> clazz = new ArrayList<>();
Enumeration<URL> urlEnumeration = Thread.currentThread().getContextClassLoader().getResources(basePackage.replace(".", "/"));
while (urlEnumeration.hasMoreElements()) {
URL url = urlEnumeration.nextElement();//得到的结果大概是:jar:file:/C:/Users/ibm/.m2/repository/junit/junit/4.12/junit-4.12.jar!/org/junit
String protocol = url.getProtocol();//大概是jar
System.out.println(protocol);
if ("jar".equalsIgnoreCase(protocol)) {
//转换为JarURLConnection
JarURLConnection connection = (JarURLConnection) url.openConnection();
if (connection != null) {
JarFile jarFile = connection.getJarFile();
if (jarFile != null) {
//得到该jar文件下面的类实体
Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
while (jarEntryEnumeration.hasMoreElements()) {
/*entry的结果大概是这样:
org/
org/junit/
org/junit/rules/
org/junit/runners/*/
JarEntry entry = jarEntryEnumeration.nextElement();
String jarEntryName = entry.getName();
//这里我们需要过滤不是class文件和不在basePack包名下的类
if (jarEntryName.contains(".class") && jarEntryName.replaceAll("/",".").startsWith(basePackage)) {
String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replace("/", ".");
clazz.add(className);
}
}
}
}
}
}
return clazz;
}
/**
*doScan函数
* @param basePackage
* @param nameList
* @return
* @throws IOException
*/
private static List<String> doScan(String basePackage, List<String> nameList) throws Exception {
String classpath = ClasspathPackageScanner.class.getResource("/").getPath();
if (classpath.startsWith("file")){
return scanJar(basePackage);
}
String splashPath = dotToSplash(basePackage);
URL url = cl.getResource(splashPath); //file:/D:/WorkSpace/java/ScanTest/target/classes/com/scan
String filePath = getRootPath(url);
List<String> names = null; // contains the name of the class file. e.g., Apple.class will be stored as "Apple"
if (isJarFile(filePath)) {// 先判断是否是jar包,如果是jar包,通过JarInputStream产生的JarEntity去递归查询所有类
if (logger.isDebugEnabled()) {
logger.debug("{} 是一个JAR包", filePath);
}
names = readFromJarFile(filePath, splashPath);
} else {
if (logger.isDebugEnabled()) {
logger.debug("{} 是一个目录", filePath);
}
names = readFromDirectory(filePath);
}
for (String name : names) {
if (isClassFile(name)) {
nameList.add(toFullyQualifiedName(name, basePackage));
} else {
doScan(basePackage + "." + name, nameList);
}
}
if (logger.isDebugEnabled()) {
for (String n : nameList) {
logger.debug("找到{}", n);
}
}
return nameList;
}
private static String toFullyQualifiedName(String shortName, String basePackage) {
StringBuilder sb = new StringBuilder(basePackage);
sb.append('.');
sb.append(trimExtension(shortName));
//打印出结果
System.out.println(sb.toString());
return sb.toString();
}
private static List<String> readFromJarFile(String jarPath, String splashedPackageName) throws IOException {
if (logger.isDebugEnabled()) {
logger.debug("从JAR包中读取类: {}", jarPath);
}
JarInputStream jarIn = new JarInputStream(new FileInputStream(jarPath));
JarEntry entry = jarIn.getNextJarEntry();
List<String> nameList = new ArrayList<String>();
while (null != entry) {
String name = entry.getName();
if (name.startsWith(splashedPackageName) && isClassFile(name)) {
nameList.add(name);
}
entry = jarIn.getNextJarEntry();
}
return nameList;
}
private static List<String> readFromDirectory(String path) {
File file = new File(path);
String[] names = file.list();
if (null == names) {
return null;
}
return Arrays.asList(names);
}
private static boolean isClassFile(String name) {
return name.endsWith(".class");
}
private static boolean isJarFile(String name) {
return name.endsWith(".jar");
}
private static String getRootPath(URL url) {
String fileUrl = url.getFile();
int pos = fileUrl.indexOf('!');
if (-1 == pos) {
return fileUrl;
}
return fileUrl.substring(5, pos);
}
/**
* "cn.fh.lightning" -> "cn/fh/lightning"
* @param name
* @return
*/
private static String dotToSplash(String name) {
return name.replaceAll("\\.", "/");
}
/**
* "Apple.class" -> "Apple"
*/
private static String trimExtension(String name) {
int pos = name.indexOf('.');
if (-1 != pos) {
return name.substring(0, pos);
}
return name;
}
/**
* /application/home -> /home
* @param uri
* @return
*/
private static String trimURI(String uri) {
String trimmed = uri.substring(1);
int splashIndex = trimmed.indexOf('/');
return trimmed.substring(splashIndex);
}
}
Tags:
很赞哦! ()
相关文章
随机图文
-
maven安装jar到本地仓库
JAVA做淘宝客程序开发的时候,我用的是maven管理依赖jar包。 如何将阿里妈妈下载的jar包以及source jar安装到maven本地仓库呢? -
Springboot集成quartz定时任务可视化配置
使用quartz定时任务已经有一段时间了,今天记录一下Springboot 2.x集成Quartz。 -
mybatis plus生成实体entity没有id
总是写很多重复的增删改查毫无意义,浪费生命,于是乎准备弄一个增删改查代码生成工具。网上查了一下mybatis plus挺好的,于是乎打开官网 Quick Start!按照官网的演示栗子:// 演示 -
通过Redis限制API调用次数
最近在做微信公众号返利机器人,通过曲线救国的方式拿到的淘宝客工具商权限(用别人的App Key),在服务器搭建了透传程序。 使用过程中发现一个问题:阿里妈妈对淘宝API的调用频率有限制,报错信息反馈是40次/秒。