咱们写中间件也好,工具框架也好,写个类加载器是必须的,好比加载指定包下类,加载某个注解标记的类,某个接口的实现类等。框架
定义ClassUtil工具类,提供基本操做:ide
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; }
这样咱们一个自定义的类加载器就搞定了,后续咱们会结合到业务中去使用。ui