gpt4 book ai didi

Java 9 类路径和库路径扩展

转载 作者:塔克拉玛干 更新时间:2023-11-01 23:04:48 25 4
gpt4 key购买 nike

Java 9 已模块化,无法通过基于反射的 Java 组件进行访问。这使得大多数扩展类路径和 java.library.path 的方法在编程上无效。怎么做才对?以及如何兼容java.sql.DriverManager和javax.activation?

最佳答案

以下是对如何以“授权”方式以编程方式扩展类路径或 java.library.path 而无需反射或尝试访问非公共(public)方法或字段的数小时研究的结果。我还将展示如何绕过 java.sql.DriverManager,因为如果 JDBC 驱动程序是使用与调用类的 ClassLoader 不同的 ClassLoader 创建的,那么它的“是类授权”检查将失败。这已经在 J​​ava 8 和 Java 9 上进行了测试,并且可以在两种环境中工作(URLClassLoader 代码应该可以回到 1.1)。

这是将在整个应用程序中使用的基本类加载器:

public class MiscTools
{
private static class SpclClassLoader extends URLClassLoader
{
static
{
ClassLoader.registerAsParallelCapable();
}

private final Set<Path> userLibPaths = new CopyOnWriteArraySet<>();

private SpclClassLoader()
{
super(new URL[0]);
}

@Override
protected void addURL(URL url)
{
super.addURL(url);
}

protected void addLibPath(String newpath)
{
userLibPaths.add(Paths.get(newpath).toAbsolutePath());
}

@Override
protected String findLibrary(String libname)
{
String nativeName = System.mapLibraryName(libname);
return userLibPaths.stream().map(tpath -> tpath.resolve(nativeName)).filter(Files::exists).map(Path::toString).findFirst().orElse(super.findLibrary(libname)); }
}
private final static SpclClassLoader ucl = new SpclClassLoader();

/**
* Adds a jar file or directory to the classpath. From Utils4J.
*
* @param newpaths JAR filename(s) or directory(s) to add
* @return URLClassLoader after newpaths added if newpaths != null
*/
public static ClassLoader addToClasspath(String... newpaths)
{
if (newpaths != null)
try
{
for (String newpath : newpaths)
if (newpath != null && !newpath.trim().isEmpty())
ucl.addURL(Paths.get(newpath.trim()).toUri().toURL());
}
catch (IllegalArgumentException | MalformedURLException e)
{
RuntimeException re = new RuntimeException(e);
re.setStackTrace(e.getStackTrace());
throw re;
}
return ucl;
}

/**
* Adds to library path in ClassLoader returned by addToClassPath
*
* @param newpaths Path(s) to directory(s) holding OS library files
*/
public static void addToLibraryPath(String... newpaths)
{
for (String newpath : Objects.requireNonNull(newpaths))
ucl.addLibPath(newpath);
}
}

在 main() 的早期放置以下代码来处理诸如 javax.activation 之类的事情。

Thread.currentThread().setContextClassLoader(MiscTools.addToClasspath());

所有线程(包括由 java.util.concurrent.Executors 创建的线程)都继承上下文 ClassLoader。

对于从扩展类路径加载的类,使用以下代码:

try
{
Class.forName(classname, true, MiscTools.addToClasspath(cptoadd);
}
catch (ClassNotFoundException IllegalArgumentException | SecurityException e)
{
classlogger.log(Level.WARNING, "Error loading ".concat(props.getProperty("Class")), e);
}

最后,如何绕过 java.sql.DriverManager,它会检查 DriverManager.getDriver() ClassLoader 的调用类是否与用于加载 JDBC 驱动程序的类加载器相同(如果加载调用类则不会)由应用程序 ClassLoader 加载,但驱动程序是使用 SpclClassLoader 加载的)。

private final static CopyOnWriteArraySet<Driver> loadedDrivers = new CopyOnWriteArraySet<>();

private static Driver isLoaded(String drivername, String... classpath) throws ClassNotFoundException
{
Driver tdriver = loadedDrivers.stream().filter(d -> d.getClass().getName().equals(drivername)).findFirst().orElseGet(() ->
{
try
{
Driver itdriver = (Driver) Class.forName(drivername, true, addToClasspath(classpath)).newInstance();
loadedDrivers.add(itdriver);
return itdriver;
}
catch (ClassNotFoundException | IllegalAccessException | InstantiationException e)
{
return null;
}
});
if (tdriver == null)
throw new java.lang.ClassNotFoundException(drivername + " not found.");
return tdriver;
}

isLoader 确保我们在提供请求的驱动程序时不会加载一堆具有所有额外开销的相同驱动程序。缺点是它需要知道 JDBC 类的类名(每个人都发布这个),而不仅仅是 DriverManager 执行的 URL 搜索,但 DriverManager 要求 JDBC 类在启动时加载,而不必执行 Class.forName 函数。

希望这会帮助其他人避免我花费大量时间为我编写的应用程序改进此方法,该应用程序在许多平台和许多配置中使用,需要能够根据属性中提供的类路径加载类文件并扩展 library.path 以使用不在默认 library.path 中的 native 库(也在属性文件中描述)。

关于Java 9 类路径和库路径扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42052856/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com