Java扫描包
Posted 疯狂的妞妞
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java扫描包相关的知识,希望对你有一定的参考价值。
在Java中,经常会有 “ 扫描某个包,然后找出全部的Class ” 的需求,Spring对这方面提供了支持,直接用即可,
Reflections这个工具包也很不错,Maven的依赖如下:
(之前写Hessian服务的时候都介绍过了)
<dependency> <groupId>org.reflections</groupId> <artifactId>reflections</artifactId> <version>0.9.10</version> </dependency>
Java扫描包
因为是偏底层的东西,自己编码虽然可以实现,但是代码安全会是一个非常麻烦、并且难以解决的问题;
以下代码,扫描自己的代码完全没问题,扫描别人代码的前提,必须保证代码不是瞎写的,.class文件确定可以被转换为Class对象的;
(当作是学习和交流吧,改进方案是对.class文件进行校验,校验通过之后,再将.class文件转换为Class对象,如果有兴趣自己继续完善吧,我已经弃坑了)。
import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.nio.channels.WritableByteChannel; import java.util.ArrayList; import java.util.List; import com.sea.common.util.Resource; import com.sea.common.util.StrStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 编译任意class文件,需要保证class文件可用,否则ERROR * * @author ChenSS 2017年8月25日上午10:04:38 * */ @Deprecated public class MyClassLoader extends ClassLoader{ private static Logger logger = LoggerFactory.getLogger(ClassLoader.class); public MyClassLoader() { super(Resource.getClassLoader()); } public static void main(String[] args) throws ClassNotFoundException { MyClassLoader loader = new MyClassLoader(); try { List<Class<?>> clazz = loader.load("C:/Users/ChenSS/Desktop/代码测试/build/classes/", "com.css.common.util"); System.out.println(clazz); } catch (Exception e) { e.printStackTrace(); } } public List<Class<?>> load(String location, String pkg) { return load(new File(location), pkg); } public List<Class<?>> load(File file, String pkg) { //StrStream是自定义的字符串校验工具,用于查找前缀是pkg(包名)、并且不包含美元符的文件 StrStream stream = new StrStream().prefix(pkg).notExists(‘$‘); return load(file, stream); } public List<Class<?>> load(File file, StrStream stream) { List<Class<?>> classes = new ArrayList<>(); if (file.exists() && file.isDirectory()) { for (File dir : likeFile(file, "", stream)) { if (dir.isDirectory()) { traverseFile(dir, dir.getName(), classes, stream); } else { // 根目录的class } } } return classes; } /** * 递归搜索全部文件,查找全部.class文件 * @param dir * @param pkg * @param classes * @param stream */ public void traverseFile(File dir, String pkg, List<Class<?>> classes, StrStream stream) { for (File file : likeFile(dir, pkg, stream)) { if (file.isDirectory()) { //文件夹就遍历下一级目录 traverseFile(file, pkg + ‘.‘ + file.getName(), classes, stream); } else { //根据.class文件直接生成Class<?> String className = null; try { String fileName = file.getName(); className = pkg + ‘.‘ + fileName.substring(0, fileName.length() - 6); Class<?> clazz = format(file, className); logger.debug(clazz.toString()); classes.add(clazz); } catch (Exception e) { e.printStackTrace(); logger.error(className + " : load error"); continue; } } } } public Class<?> format(String fileName, String className) throws Exception { return format(new File(fileName), className); } /** * 从.class文件直接生成Class<?>,从IO到对象的转换,IO是未经过检查的; * 因此,如果想要使用此类,必须保证全部的.class文件可以创建Java类; * 手动编码、并且编译通过的.class文件不会有问题; * 扫描自己不熟悉的.class文件时,如果.class文件内容是错误的,有可能产生强制中断主函数的Error。 */ public Class<?> format(File file, String className) throws Exception { FileInputStream fis = new FileInputStream(file); FileChannel fileC = fis.getChannel(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); WritableByteChannel wbc = Channels.newChannel(baos); ByteBuffer buffer = ByteBuffer.allocateDirect(1024); while (fileC.read(buffer) > 0) { buffer.flip(); wbc.write(buffer); buffer.clear(); } byte[] b = baos.toByteArray(); IOUtils.closeQuietly(baos, wbc, fileC, fis); return defineClass(className, b, 0, b.length); } /** * * @param dir 文件夹 * @param string 路径名 * @param stream 字符串校验类 * @return */ public static File[] likeFile(File dir, String string, StrStream stream) { return dir.listFiles(new FileFilter() { @Override public boolean accept(File file) { return stream.string(string).like() || file.isFile(); } }); } }
以上是关于Java扫描包的主要内容,如果未能解决你的问题,请参考以下文章