利用URLClassLoader读取Jar包并反射类(利用Tomcat源码)

第一次写博客,写的不好请见谅。


背景:在公司内部项目中碰到了一个需求,我需要读取本地jar包然后反射其中的实体类来获取其类名属性等字段并保存。

分析:显然,我们首先需要用到反射,但是反射需要有类加载器来加载类。比如classLoader.load("com.test.Test");对加载器不了解的朋友可以自行百度。因为是读的本地的jar包,我们当前web用的appClassLoader显然不够用,也无法load本地的类,因此我们可以自己使用URLClassLoader创建一个加载器。(在这里我是用了tomcat生成自定义classloader的方法,很简单)。

方法:将jar存在项目根路径下,创建ClassLoader之前获取jar包的所有路径即可。

实施

/**
 * 创建classloader(调用了tomcatapi * @return
 * @throws Exception
 */
private ClassLoader createClassLoader() throws Exception {
    //在这里拿到存在本地的jar包的路径
    //模仿tomcat的处理方式
    String value = JarProperties.getProperty("jar.path");
    if (value == null) {
        return null;
    }
    //处理字符串路径
    value = replace(value);
    List<ClassLoaderFactory.Repository> repositories = new ArrayList<>();
    //分割成路径数组
    String[] repositoryPaths = getPaths(value);

    for (String repository : repositoryPaths) {
        // Local repository
        if (repository.endsWith("*.jar")) {
            repository = repository.substring
                    (0, repository.length() - "*.jar".length());
            repositories.add(
                    new ClassLoaderFactory.Repository(repository, ClassLoaderFactory.RepositoryType.GLOB));
        } else if (repository.endsWith(".jar")) {
            repositories.add(
                    new ClassLoaderFactory.Repository(repository, ClassLoaderFactory.RepositoryType.JAR));
        } else {
            repositories.add(
                    new ClassLoaderFactory.Repository(repository, ClassLoaderFactory.RepositoryType.DIR));
        }
    }
    return ClassLoaderFactory.createClassLoader(repositories, null);
}
	其中JarProperties如下:
 
 
public class JarProperties {

    private static final Logger logger = LoggerFactory.getLogger(JarProperties.class);

    private static Properties properties = null;

    static {
        loadProperties();
    }

    /**
     * @param name The property name
     * @return specified property value
     */
    public static String getProperty(String name) {
        return properties.getProperty(name);
    }

    private static void loadProperties() {
        InputStream is = null;
        try {
            ClassLoader cl = JarProperties.class.getClassLoader();
            URL url = cl.getResource("jar.properties");
            if (url != null) {
                is = url.openStream();
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("url打开stream错误");
//            logger.error(e.getMessage() + "没有找到.properties文件");
        }

        if (is != null) {
            try {
                properties = new Properties();
                properties.load(is);
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("加载jar.properties文件出错");
            } finally {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    logger.error("无法关闭jar.properties" + e);
                }
            }
        }

        if (is == null) {
            // Do something
            logger.error("没有找到jar.properties文件");
            // That's fine - we have reasonable defaults.
            properties = new Properties();
        }
    }
}
	jar.properties:
 
 
jar.path = "${authority.home}/jar","${authority.home}/jar/*.jar"
然后在ClassLoaderFactory.createClassLoader(repositories, null)中:
/**
 * Create and return a new class loader, based on the configuration
 * defaults and the specified directory paths:
 *
 * @param repositories List of class directories, jar files, jar directories
 *                     or URLS that should be added to the repositories of
 *                     the class loader.
 * @param parent Parent class loader for the new class loader, or
 *  <code>null</code> for the system class loader.
 * @return the new class loader
 *
 * @exception Exception if an error occurs constructing the class loader
 */
public static ClassLoader createClassLoader(List<Repository> repositories,
                                            final ClassLoader parent)
    throws Exception {

    if (log.isDebugEnabled())
        log.debug("Creating new class loader");

    // Construct the "class path" for this class loader
    Set<URL> set = new LinkedHashSet<>();

    if (repositories != null) {
        for (Repository repository : repositories)  {
            if (repository.getType() == RepositoryType.URL) {
                URL url = buildClassLoaderUrl(repository.getLocation());
                if (log.isDebugEnabled())
                    log.debug("  Including URL " + url);
                set.add(url);
            } else if (repository.getType() == RepositoryType.DIR) {
                File directory = new File(repository.getLocation());
                directory = directory.getCanonicalFile();
                if (!validateFile(directory, RepositoryType.DIR)) {
                    continue;
                }
                URL url = buildClassLoaderUrl(directory);
                if (log.isDebugEnabled())
                    log.debug("  Including directory " + url);
                set.add(url);
            } else if (repository.getType() == RepositoryType.JAR) {
                File file=new File(repository.getLocation());
                file = file.getCanonicalFile();
                if (!validateFile(file, RepositoryType.JAR)) {
                    continue;
                }
                URL url = buildClassLoaderUrl(file);
                if (log.isDebugEnabled())
                    log.debug("  Including jar file " + url);
                set.add(url);
            } else if (repository.getType() == RepositoryType.GLOB) {
                File directory=new File(repository.getLocation());
                directory = directory.getCanonicalFile();
                if (!validateFile(directory, RepositoryType.GLOB)) {
                    continue;
                }
                if (log.isDebugEnabled())
                    log.debug("  Including directory glob "
                        + directory.getAbsolutePath());
                String filenames[] = directory.list();
                if (filenames == null) {
                    continue;
                }
                for (int j = 0; j < filenames.length; j++) {
                    String filename = filenames[j].toLowerCase(Locale.ENGLISH);
                    if (!filename.endsWith(".jar"))
                        continue;
                    File file = new File(directory, filenames[j]);
                    file = file.getCanonicalFile();
                    if (!validateFile(file, RepositoryType.JAR)) {
                        continue;
                    }
                    if (log.isDebugEnabled())
                        log.debug("    Including glob jar file "
                            + file.getAbsolutePath());
                    URL url = buildClassLoaderUrl(file);
                    set.add(url);
                }
            }
        }
    }

    // Construct the class loader itself
    final URL[] array = set.toArray(new URL[set.size()]);
    if (log.isDebugEnabled())
        for (int i = 0; i < array.length; i++) {
            log.debug("  location " + i + " is " + array[i]);
        }

    return AccessController.doPrivileged(
            new PrivilegedAction<URLClassLoader>() {
                @Override
                public URLClassLoader run() {
                    if (parent == null)
                        return new URLClassLoader(array);
                    else
                        return new URLClassLoader(array, parent);
                }
            });
}
具体注释我就不写了,就是把路径处理一下然后放在数组中然后new URLClassLoader(array)就可以。
	大部分代码都是tomcat源码中的,我是直接用的tomcat的类完成的这个接口。所以说,多看源码还是很有帮助滴。
	
				人生第一篇博客结束!!!!!


 
 

猜你喜欢

转载自blog.csdn.net/opiqi/article/details/76269867