您的位置:首页 > 运维架构 > Tomcat

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

2017-07-28 17:13 399 查看
第一次写博客,写的不好请见谅。

背景:在公司内部项目中碰到了一个需求,我需要读取本地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 {
r
d374
epositories.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的类完成的这个接口。所以说,多看源码还是很有帮助滴。
人生第一篇博客结束!!!!!



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: