我们写中间件也好,工具框架也好,写个类加载器是必须的,比如加载指定包下类,加载某个注解标记的类,某个接口的实现类等。
定义ClassUtil工具类,提供基本操作:
public final class Classutil{
/*
获取类加载器
*/
public static ClassLoader getClassLoader(){
return Thread.currentThread().getContextClassLoader();
}
// 为提升性能,isInitialized默认为false
public static Class<?> loadClass(String className, boolean isInitialized){
Class<?> cls;
try{
cls = Class.forName(className,isInitialized,getClassLoader());
}catch(ClassNotFoundException e){
throw new RuntimeException(e);
}
return cls;
}
}
获取指定包下所有的类,需要将包名转换为文件路径,读class文件或者jar包,再去进行类加载:
public static Set<Class<?>> getClassSet(String packageName){
Set<Class<?>> classSet = new HashSet<Class<?>>();
try{
Enumeration<URL> urls = getClassLoader().getResources(packageName.replace(".","/"));
while(urls.hasMoreElements()){
URL url = urls.nextElement();
if(url != null){
String protocol = url.getProtocol();
if(protocol.equals("file")){
String packagePath = url.getPath().replaceAll("%20","");
addClass(classSet,packagePath,packageName);
}else if (protocol.equals("jar")){
JarURLConnection jarURLConnection = (JarURLConnection)url.openConnection();
if(jarURLConnection != null){
JarFile jarFile = jarURLConnection.getJarFile();
if(jarFile != null){
Enumeration<JarEntity> jarEntities = jarFile.entries();
while(jarEntries.hasMoreElements()){
JarEntity jarEntity = jarEntities.nextElement();
String jarEntityName = jarEntity.getName();
if(jarEntityName.endWith(".class")){
String className = jarEntryName.substring(0,jarEntryName.lastIndexOf(".")).replaceAll("/",".");
doAddClass(classSet,ClassName);
}
}
}
}
}
}
}
}catch(Exception e){
throw new RuntimeException(e);
}
return classSet;
}
private static void addClass(Set<Class<?>> classSet, String packagePath, String packageName){
File[] files = new File(packagePaht).listFiles(new FileFilter(){
@Override
public boolean accept(File file){
return (file.isFie() && file.getName().endWith(".class")) || file.isDirectory();
}
});
for(File file:files){
String fileName = file.getName();
if(file.isFile()){
Stirng className = fileName.substring(0,fileName.lastIndexOf("."));
if(!StringUtils.isBlank(packageName)){
className = packageName + "."+className;
}
doAddClass(classSet, className);
}else{
String subPackagePath = fileName;
if(!StringUtils.isBlank(packagePath)){
subPackagePath = packagePath + "/"+subPackagePath;
}
String subPackageName = fileName;
if(!StringUtils.isBlank(packageName)){
subPackageName = packageName + "."+subPackageName;
}
addClass(classSet,subPackagePath,subPackageName);
}
}
}
private static void doAddClass(Set<Class<?>> classSet, String className){
Class<?> cls = loadClass(className, false);
classSet.add(cls);
}
在容器(比如Spring)启动时进行类加载:
private static Set<Class<?>> CLASS_SET;
public static void init(String basePackage){
CLASS_SET = ClassBuilder.getClassSet(basePackage);
}
/* 获取包下所有的类 */
public static Set<Class<?>> getClassSet(){
return CLASS_SET;
}
/* 获取包下所有指定注解的类 */
pubic static Set<Class<?>> getAnnoClassSet<Class<?> extends Annotation annoClass>{
Set<Class<?>> classSet = new HashSet<>();
for(Class<?> cls : CLASS_SET){
if(cls.isAnnotationPresent(annoClass)){
classSet.add(cls);
}
}
return classSet;
}
这样我们一个自定义的类加载器就搞定了,后续我们会结合到业务中去使用。