首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 开源软件 >

类加载器的扩充应用

2012-11-15 
类加载器的扩展应用根据Java类加载器ClassLoader的特性,结合目录相关的递归索引算法,我实现了如下的应用扩

类加载器的扩展应用
    根据Java类加载器ClassLoader的特性,结合目录相关的递归索引算法,我实现了如下的应用扩展:
通过指定的包名加载该包下的所有.class后缀名文件,并转换为Class对象列表;通过指定的Class对象,检索CLASSPATH下所有的类,筛选出该Class对象的子类(实现类),并转换为Class对象列表;加载器支持jar协议和file协议。
    关键代码,获取当前线程的类加载器中加载的符合包名的目录列表,循环目录进行处理:

/** * 根据包名、类或接口的反射对象来获取符合条件的反射对象列表,特殊情况如下: * <ul> * <li>如果传入参数cls为null,则程序获取指定包名下所有反射对象。</li> * </ul> *  * @param pkg 指定的包名,非空。 * @param cls 指定的反射对象。 * @return 反射对象列表。 * @throws IOException 执行时可能抛出的异常。 * @throws ClassNotFoundException 执行时可能抛出的异常。 */protected Set<Class<?>> getClassesByPackageOrSuperClass(String pkg, Class<?> cls) throws IOException, ClassNotFoundException {Set<Class<?>> classes = new HashSet<Class<?>>();String relativePath = pkg.replace('.', '/');// TODO(Liuzheng): 获取所有包含指定相对路径的URL。Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(relativePath);while (urls.hasMoreElements()) {URL url = urls.nextElement();String protocol = url.getProtocol();if ("jar".equals(protocol)) {JarFile jarFile = ((JarURLConnection) url.openConnection()).getJarFile();Enumeration<JarEntry> jarEntries = jarFile.entries();while (jarEntries.hasMoreElements()) {JarEntry jarEntry = jarEntries.nextElement();String jarPath = jarEntry.getName();// TODO(Liuzheng): 通过正则表达式筛选出标准类路径。Pattern pattern = Pattern.compile("(^" + relativePath + ".*)\\.class");Matcher matcher = pattern.matcher(jarPath);if (matcher.find()) {String className = matcher.group(1).replace('/', '.');try {// TODO(Liuzheng): 如果类加载器加载失败,则跳转至错误处理程序。Class<?> targetClass = Thread.currentThread().getContextClassLoader().loadClass(className);if (cls == null || cls.isAssignableFrom(targetClass)) classes.add(targetClass);} catch (NoClassDefFoundError e) {logger.error("找不到指定的类:" + e.getLocalizedMessage());}}}} else if ("file".equals(protocol)) {File file = new File(URLDecoder.decode(url.getFile(), "UTF-8"));// TODO(Liuzheng): 通过根目录和后缀名递归获取所有子目录。Set<String> classNames = getClassNamesByRootFileAndPackage(file, pkg);for (String className : classNames) {try {// TODO(Liuzheng): 如果类加载器加载失败,则跳转至错误处理程序。Class<?> targetClass = Thread.currentThread().getContextClassLoader().loadClass(className);if (cls == null || cls.isAssignableFrom(targetClass)) classes.add(targetClass);} catch (NoClassDefFoundError e) {logger.error("找不到指定的类:" + e.getLocalizedMessage());}}}}return classes;}

    关键代码,通过递归算法,检索所有子目录中符合条件的class文件,并转换为类名列表:
/** * 根据指定的目录和后缀名遍历子目录,获取目录下的所有类的类名列表。 *  * @param file 指定的目录。 * @param sfx 指定的后缀名。 * @return 类名列表。 */public Set<String> getClassNamesByRootFileAndPackage(File file, String pkg) {if (pkg != null && !pkg.isEmpty()) pkg += '.';Set<String> files = new HashSet<String>();if (file.isDirectory()) {File[] fileArray = file.listFiles(new FileFilter() {@Overridepublic boolean accept(File file) {return file.isDirectory() || file.getName().endsWith(".class");}});for (File subFile : fileArray) {if (subFile.isDirectory()) files.addAll(getClassNamesByRootFileAndPackage(subFile, pkg + subFile.getName()));else files.add(pkg + subFile.getName().replace(".class", ""));}}return files;}

热点排行