咱們寫中間件也好,工具框架也好,寫個類加載器是必須的,好比加載指定包下類,加載某個註解標記的類,某個接口的實現類等。框架
定義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