第一次写博客,写的不好请见谅。
背景:在公司内部项目中碰到了一个需求,我需要读取本地jar包然后反射其中的实体类来获取其类名、属性等字段并保存。
分析:显然,我们首先需要用到反射,但是反射需要有类加载器来加载类。比如classLoader.load("com.test.Test");对加载器不了解的朋友可以自行百度。因为是读的本地的jar包,我们当前web用的appClassLoader显然不够用,也无法load本地的类,因此我们可以自己使用URLClassLoader创建一个加载器。(在这里我是用了tomcat生成自定义classloader的方法,很简单)。
方法:将jar存在项目根路径下,创建ClassLoader之前获取jar包的所有路径即可。
实施:
/** * 创建classloader(调用了tomcat的api) * @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的类完成的这个接口。所以说,多看源码还是很有帮助滴。
人生第一篇博客结束!!!!!