我解决了一个非常具体的问题,其解决方案似乎是基本的:
我的(Spring)应用程序的类加载器层次结构是这样的: SystemClassLoader -> PlatformClassLoader -> AppClassLoader
如果我使用Java CompleteableFuture来运行线程.该ContextClassLoader线程的是: SystemClassLoader -> PlatformClassLoader -> ThreadClassLoader
因此,AppClassLoader虽然我必须访问任何类,但我无法访问任何类,因为所有外部库类都驻留在那里.
源代码库非常大,所以我不希望/不能将所有与线程相关的部分重写为其他内容(例如,将自定义执行程序传递给每个调用).
所以我的问题是:我怎样才能创建线程,例如CompleteableFuture.supplyAsync()使用AppClassLoader父母作为父母?(而不是PlatformClassloader)
我发现ForkJoinPool用于创建线程.但在我看来,一切都是静态的和最终的.所以我怀疑即使在系统属性中设置自定义ForkJoinWorkerThreadFactory也会有所帮助.或者是吗?
编辑以回答评论中的问题:
你在哪里部署?这是在jetty/tomcat /任何JEE容器内运行吗?
你有什么确切的问题?
您提交给supplyAsync()的作业是从AppClassLoader创建的,不是吗?
在supplyAsync从被称为MainThread它使用AppClassLoader.但是,调试应用程序会显示所有此类线程都具有PlatformClassLoader父级.至于我的理解,这是因为ForkJoinPool.commonPool()是在应用程序启动期间构建的(因为它是静态的),所以使用默认的类加载器作为父类PlatformClassLoader.因此,此池中的所有线程都将PlatformClassLoader作为ContextClassLoader的父级(而不是AppClassLoader).
当我在内部创建自己的执行程序MainThread并将此执行程序传递给supplyAsync所有工作时 - 我可以在调试期间看到确实现在AppClassLoader是我的父项ThreadClassLoader.这似乎证实了我在第一种情况下的假设,即公共池MainThread至少不是在它自己使用时创建的 …
我有一个在WAS 6上运行的JEE应用程序.它需要将类加载器顺序设置为"首先加载应用程序类加载器的类",并将WAR类加载器策略选项设置为"应用程序的单个类加载器".
是否可以在EAR文件中指定这些选项,无论是在ibm-web-bnd.xmi文件还是其他文件中,因此管理员无需手动更改这些设置?
由于应用程序是通过自动脚本部署的,并且负责部署的人员不在现场,而且出于其他一些政治原因,这将有很大帮助!
是否保证(默认的,系统)Java类加载器不会尝试加载正在运行的代码中未引用的类?我的意思是几个例子:
framework.jar我知道的包含对其他library.jar类的引用,但我只使用不包含这些引用的框架的这一部分.遗漏是否安全library.jar?快速测试它看起来像上面假设的那样工作,无论如何加载未使用的类没有多大意义,但是有什么保证吗?
另外:似乎我的"静态块在第一次加载类时运行"上面的语句有些不正确.绝对可以加载类(一件事)而不运行它们(另一件事).所以我对这两种情况都感兴趣; 保证类没有加载,而不是运行.
我想使用URLClassLoader加载并执行外部jar文件.
从中获取"Main-Class"的最简单方法是什么?
我刚刚与我的朋友讨论了使用类名调用静态方法,并尝试了这个代码并期望它在运行时抛出NPE.但事实证明它是dint.我只是想了解执行顺序.
public class One {
public static void method() {
System.out.println("in static one");
}
}
public class Two {
static One o;
public static void main(String[] args) {
o.method(); // expected NPE here, as o is null
}
}
Run Code Online (Sandbox Code Playgroud)
我知道静态方法应该用它们的类名调用,我甚至知道当我们用实例调用静态方法时IDE会给出编译器警告.但我们也可以通过创建一个实例来调用它们,但是,我从来没有在这里创建过一个实例,o应该得到它的默认值null,因此调用o.method()应该在运行时抛出一个NPE,但事实并非如此.你们能否详细说明这段代码中的执行顺序.
java.lang.IllegalAccessError:尝试从类Entity访问字段ConcreteEntity.instance
好的,这是交易.我试图访问ConcreteEntity.instance哪个是默认情况下存在的访问类型默认的字段,ClassLoader并且Entity.getInstance是子项中存在的方法ClassLoader.
现在请记住,他们都在同一个包中,但是IllegalAccessError正在抛出.有没有解决这个问题,不涉及我的实际加载内同一实体类的解决方案ClassLoader为ConcreteEntity?
0 new #14 <Entity>
3 dup
4 aload_0
5 invokevirtual #18 <Adapter.getInstance>
8 checkcast #20 <sl>
11 getfield #24 <sl.d>
14 invokespecial #25 <Entity.<init>>
17 areturn
Run Code Online (Sandbox Code Playgroud)
通过jclasslib at检索的字节码是"编译后"生成的异常.
谢谢Gamb清理帖子.
我正在尝试使用这种代码动态加载JDBC驱动程序:
try{
URL[] url={new URL("file:libs/mysql-connector-java-5.1.21.jar")};
URLClassLoader loader = new URLClassLoader(url, System.class.getClassLoader());
loader.loadClass(drivername);
Enumeration<Driver> drivers = DriverManager.getDrivers();
while(drivers.hasMoreElements()){
Driver driver = drivers.nextElement();
System.out.println("driver:"+driver);
}
Class.forName(drivername, true, loader);
drivers = DriverManager.getDrivers();
while(drivers.hasMoreElements()){
Driver driver = drivers.nextElement();
System.out.println("driver:"+driver);
}
Connection connect = DriverManager.getConnection(jdbcurl, user,
password);
return connect;
}
catch (MalformedURLException e){
e.printStackTrace();
return null;
}
Run Code Online (Sandbox Code Playgroud)
第一个while循环显示类路径的驱动程序:
driver:sun.jdbc.odbc.JdbcOdbcDriver@35712651
driver:oracle.jdbc.OracleDriver@58df0438
driver:com.ibm.db2.jcc.DB2Driver@525c7734
driver:SQLServerDriver:1
Run Code Online (Sandbox Code Playgroud)
第二个循环显示相同的驱动程序,但没有MySQL驱动程序.
我的问题是为什么?我错过了什么?
我在JavaDoc中DriverManager读到,如果驱动程序已加载,则每个驱动程序都会尝试通过drivermanager注册自己.在我的代码中,这应该是loader.loadClass(drivername);.我认为这段代码应该调用静态部分,例如:
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register …Run Code Online (Sandbox Code Playgroud) 我正在研究一个安全性很大的项目.要求是密封我们的罐子.
由于我们密封了罐子,我们的很多junit测试失败了,出现以下错误:
java.lang.SecurityException: sealing violation: package [a.dependency.package] is sealed
at java.net.URLClassLoader.defineClass(URLClassLoader.java:234)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2427)
at java.lang.Class.getDeclaredMethods(Class.java:1791)
at org.mockito.cglib.core.ReflectUtils.addAllMethods(ReflectUtils.java:349)
at org.mockito.cglib.proxy.Enhancer.getMethods(Enhancer.java:422)
at org.mockito.cglib.proxy.Enhancer.generateClass(Enhancer.java:457)
at org.mockito.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:217)
at org.mockito.cglib.proxy.Enhancer.createHelper(Enhancer.java:378)
at org.mockito.cglib.proxy.Enhancer.createClass(Enhancer.java:318)
at org.mockito.internal.creation.jmock.ClassImposterizer.createProxyClass(ClassImposterizer.java:93)
at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:50)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:54)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:45)
at org.mockito.Mockito.spy(Mockito.java:991)
at [...]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71) …Run Code Online (Sandbox Code Playgroud) 在Java 7中加载KeyStore时,类加载器被泄露.
我已经使用Tomcat 7.0.47中的"Find Leaks"功能和classloader-leak-prevention确认了这一点.这是测试代码,带有@Configuration泄漏的webapp和带有@Controller泄漏的webapp.
基本上这些线为我造成了泄漏:
InputStream is = null;
try {
is = new FileInputStream("./app.truststore");
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(is, "changeit".toCharArray());
} catch (Exception e) {
System.out.println(e);
} finally {
if (is != null) {
is.close();
}
}
Run Code Online (Sandbox Code Playgroud)
如果我删除KeyStore.load()一切正常,但这显然不是一个有效的解决方案.
它不适用于Oracle JDK 1.7u15,u17,u21,u25,u40和u45以及OpenJDK 1.7u40和u45.
它适用于Oracle JDK 1.6u39,u41,u43和45以及OpenJDK 1.6.0.
这是在Microsoft Windows Server 2008 R2 Standard 64 Bit上测试的.OpenJDKs是alexkasko在GitHub上的最新非官方版本.
有谁知道可能导致Classloader泄漏的原因是什么?我尝试使用堆转储并调用"GC根目录的最短路径",但没有返回任何结果.
我对这两个类加载器非常困惑.在谈论Java类加载器的层次结构时,通常会提到引导类加载器和ext类加载器以及第三个(系统类加载器或应用程序类加载器).
为了更准确,我检查了JDK的源代码.在课堂上Launcher,有代码:
loader = AppClassLoader.getAppClassLoader(extcl);
Run Code Online (Sandbox Code Playgroud)
在课堂上ClassLoader,方法:
getSystemClassloader()
Run Code Online (Sandbox Code Playgroud)
还说系统类加载器用于启动应用程序.
那么哪个是层次结构中的第三个,还是两个类加载器相同?
classloader ×10
java ×10
jdbc ×1
memory-leaks ×1
mockito ×1
sealed ×1
spring ×1
static ×1
websphere ×1