add setClassLoader

This commit is contained in:
Looly 2019-10-05 12:33:48 +08:00
parent 1ddc01453f
commit 476285b302
3 changed files with 93 additions and 66 deletions

View File

@ -8,6 +8,7 @@
### 新特性 ### 新特性
* 【all】 修复注释中的错别字issue#I12XE6@Gitee * 【all】 修复注释中的错别字issue#I12XE6@Gitee
* 【core】 CsvWriter支持其它类型的参数issue#I12XE3@Gitee * 【core】 CsvWriter支持其它类型的参数issue#I12XE3@Gitee
* 【core】 ClassScaner支持自定义ClassLoader
### Bug修复 ### Bug修复
* 【all】 修复阶乘计算错误bugissue#I12XE4@Gitee * 【all】 修复阶乘计算错误bugissue#I12XE4@Gitee

View File

@ -1,5 +1,12 @@
package cn.hutool.core.lang; package cn.hutool.core.lang;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.EnumerationIter;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.*;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
@ -12,48 +19,54 @@ import java.util.Set;
import java.util.jar.JarEntry; import java.util.jar.JarEntry;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.EnumerationIter;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
/** /**
* 类扫描器 * 类扫描器
* *
* @author looly * @author looly
* @since 4.1.5 * @since 4.1.5
*
*/ */
public class ClassScaner implements Serializable{ public class ClassScaner implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** 包名 */ /**
* 包名
*/
private String packageName; private String packageName;
/** 包名,最后跟一个点,表示包名,避免在检查前缀时的歧义 */ /**
* 包名最后跟一个点表示包名避免在检查前缀时的歧义
*/
private String packageNameWithDot; private String packageNameWithDot;
/** 包路径,用于文件中对路径操作 */ /**
* 包路径用于文件中对路径操作
*/
private String packageDirName; private String packageDirName;
/** 包路径用于jar中对路径操作在Linux下与packageDirName一致 */ /**
* 包路径用于jar中对路径操作在Linux下与packageDirName一致
*/
private String packagePath; private String packagePath;
/** 过滤器 */ /**
* 过滤器
*/
private Filter<Class<?>> classFilter; private Filter<Class<?>> classFilter;
/** 编码 */ /**
* 编码
*/
private Charset charset; private Charset charset;
/** 是否初始化类 */ /**
* 类加载器
*/
private ClassLoader classLoader;
/**
* 是否初始化类
*/
private boolean initialize; private boolean initialize;
private Set<Class<?>> classes = new HashSet<Class<?>>(); private Set<Class<?>> classes = new HashSet<>();
/** /**
* 扫描指定包路径下所有包含指定注解的类 * 扫描指定包路径下所有包含指定注解的类
* *
* @param packageName 包路径 * @param packageName 包路径
* @param annotationClass 注解类 * @param annotationClass 注解类
* @return 类集合 * @return 类集合
*/ */
@ -70,7 +83,7 @@ public class ClassScaner implements Serializable{
* 扫描指定包路径下所有指定类或接口的子类或实现类 * 扫描指定包路径下所有指定类或接口的子类或实现类
* *
* @param packageName 包路径 * @param packageName 包路径
* @param superClass 父类或接口 * @param superClass 父类或接口
* @return 类集合 * @return 类集合
*/ */
public static Set<Class<?>> scanPackageBySuper(String packageName, final Class<?> superClass) { public static Set<Class<?>> scanPackageBySuper(String packageName, final Class<?> superClass) {
@ -145,7 +158,7 @@ public class ClassScaner implements Serializable{
* *
* @param packageName 包名所有包传入""或者null * @param packageName 包名所有包传入""或者null
* @param classFilter 过滤器无需传入null * @param classFilter 过滤器无需传入null
* @param charset 编码 * @param charset 编码
*/ */
public ClassScaner(String packageName, Filter<Class<?>> classFilter, Charset charset) { public ClassScaner(String packageName, Filter<Class<?>> classFilter, Charset charset) {
packageName = StrUtil.nullToEmpty(packageName); packageName = StrUtil.nullToEmpty(packageName);
@ -165,16 +178,16 @@ public class ClassScaner implements Serializable{
public Set<Class<?>> scan() { public Set<Class<?>> scan() {
for (URL url : ResourceUtil.getResourceIter(this.packagePath)) { for (URL url : ResourceUtil.getResourceIter(this.packagePath)) {
switch (url.getProtocol()) { switch (url.getProtocol()) {
case "file": case "file":
scanFile(new File(URLUtil.decode(url.getFile(), this.charset.name())), null); scanFile(new File(URLUtil.decode(url.getFile(), this.charset.name())), null);
break; break;
case "jar": case "jar":
scanJar(URLUtil.getJarFile(url)); scanJar(URLUtil.getJarFile(url));
break; break;
} }
} }
if(CollUtil.isEmpty(this.classes)) { if (CollUtil.isEmpty(this.classes)) {
scanJavaClassPaths(); scanJavaClassPaths();
} }
@ -190,11 +203,20 @@ public class ClassScaner implements Serializable{
this.initialize = initialize; this.initialize = initialize;
} }
/**
* 设置自定义的类加载器
*
* @param classLoader 类加载器
* @since 4.6.9
*/
public void setClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
// --------------------------------------------------------------------------------------------------- Private method start // --------------------------------------------------------------------------------------------------- Private method start
/** /**
* 扫描Java指定的ClassPath路径 * 扫描Java指定的ClassPath路径
*
* @return 扫描到的类
*/ */
private void scanJavaClassPaths() { private void scanJavaClassPaths() {
final String[] javaClassPaths = ClassUtil.getJavaClassPaths(); final String[] javaClassPaths = ClassUtil.getJavaClassPaths();
@ -209,7 +231,7 @@ public class ClassScaner implements Serializable{
/** /**
* 扫描文件或目录中的类 * 扫描文件或目录中的类
* *
* @param file 文件或目录 * @param file 文件或目录
* @param rootDir 包名对应classpath绝对路径 * @param rootDir 包名对应classpath绝对路径
*/ */
private void scanFile(File file, String rootDir) { private void scanFile(File file, String rootDir) {
@ -263,9 +285,15 @@ public class ClassScaner implements Serializable{
* @return 加载的类 * @return 加载的类
*/ */
private Class<?> loadClass(String className) { private Class<?> loadClass(String className) {
ClassLoader loader = this.classLoader;
if (null == loader) {
loader = ClassLoaderUtil.getClassLoader();
this.classLoader = loader;
}
Class<?> clazz = null; Class<?> clazz = null;
try { try {
clazz = Class.forName(className, this.initialize, ClassUtil.getClassLoader()); clazz = Class.forName(className, this.initialize, loader);
} catch (NoClassDefFoundError e) { } catch (NoClassDefFoundError e) {
// 由于依赖库导致的类无法加载直接跳过此类 // 由于依赖库导致的类无法加载直接跳过此类
} catch (UnsupportedClassVersionError e) { } catch (UnsupportedClassVersionError e) {
@ -280,23 +308,22 @@ public class ClassScaner implements Serializable{
/** /**
* 通过过滤器是否满足接受此类的条件 * 通过过滤器是否满足接受此类的条件
* *
* @param clazz * @param className 类名
* @return 是否接受
*/ */
private void addIfAccept(String className) { private void addIfAccept(String className) {
if(StrUtil.isBlank(className)) { if (StrUtil.isBlank(className)) {
return; return;
} }
int classLen = className.length(); int classLen = className.length();
int packageLen = this.packageName.length(); int packageLen = this.packageName.length();
if(classLen == packageLen) { if (classLen == packageLen) {
//类名和包名长度一致用户可能传入的包名是类名 //类名和包名长度一致用户可能传入的包名是类名
if(className.equals(this.packageName)) { if (className.equals(this.packageName)) {
addIfAccept(loadClass(className)); addIfAccept(loadClass(className));
} }
} else if(classLen > packageLen){ } else if (classLen > packageLen) {
//检查类名是否以指定包名为前缀包名后加.避免类似于cn.hutool.A和cn.hutool.ATest这类类名引起的歧义 //检查类名是否以指定包名为前缀包名后加.避免类似于cn.hutool.A和cn.hutool.ATest这类类名引起的歧义
if(className.startsWith(this.packageNameWithDot)) { if (className.startsWith(this.packageNameWithDot)) {
addIfAccept(loadClass(className)); addIfAccept(loadClass(className));
} }
} }
@ -306,7 +333,6 @@ public class ClassScaner implements Serializable{
* 通过过滤器是否满足接受此类的条件 * 通过过滤器是否满足接受此类的条件
* *
* @param clazz * @param clazz
* @return 是否接受
*/ */
private void addIfAccept(Class<?> clazz) { private void addIfAccept(Class<?> clazz) {
if (null != clazz) { if (null != clazz) {

View File

@ -10,7 +10,7 @@ public class ClassScanerTest {
@Test @Test
@Ignore @Ignore
public void scanTest() { public void scanTest() {
ClassScaner scaner = new ClassScaner("cn.hutool.core.util.StrUtil", null); ClassScaner scaner = new ClassScaner("cn.hutool.core.util", null);
Set<Class<?>> set = scaner.scan(); Set<Class<?>> set = scaner.scan();
for (Class<?> clazz : set) { for (Class<?> clazz : set) {
Console.log(clazz.getName()); Console.log(clazz.getName());