我理解Class.getResource()和ClassLoader.getResource()之间有什么区别? 从自己的代码,那
getClass().getResource("/path/image.png")
Run Code Online (Sandbox Code Playgroud)
是完全相同的
getClass().getClassLoader().getResource("path/image.png")
Run Code Online (Sandbox Code Playgroud)
getClass().getClassLoader().getResource("path/image.png")
Run Code Online (Sandbox Code Playgroud)
在可执行jar文件中返回null,而
getClass().getResource("/path/image.png")
Run Code Online (Sandbox Code Playgroud)
返回正确的URL.
Since Class.getResource()代表ClassLoader.getResource()在删除前导斜杠后,我希望这些调用是相同的,但显然它们不是这种情况.即使特殊类加载器附加到特定类,每次调用它仍然应该是相同的,再次导致相同的行为.
所以,问题是:是否存在以下代码在第一次调用时返回null但第二次调用的正确URL的任何明显情况?
package com.example;
import java.net.URL;
public class ResourceTest {
public void run() {
URL iconUrl1 = getClass().getClassLoader().getResource("path/image.png");
System.out.println("ClassLoader.getResource(\"path/image.png\"): " + iconUrl1);
URL iconUrl2 = getClass().getResource("/path/image.png");
System.out.println("Class.getResource(\"/path/image.png\"): " + iconUrl2);
}
public static void main(String[] args) {
ResourceTest app = new ResourceTest();
app.run();
}
}
Run Code Online (Sandbox Code Playgroud) 我有一个带有一些有趣行为的J2EE应用程序......堆似乎表现良好,随着时间的推移随着垃圾收集而增长和缩小.没有明显的整体长期堆扩展.然而,在我们遇到MaxMetaspace并遇到OOME之前,元空间一直稳定地以每小时20 Mb的速度增长.我尝试了并行和G1垃圾收集器(jdk1.8.0_40).
应用程序在执行期间没有重新部署,因此它似乎不是典型的类加载器泄漏.有没有人建议如何追查这个泄漏的来源?
编辑:更新以回应Ani B.
编辑2:添加了更新的PluginSecurityManager.
我的应用程序有一个插件机制,第三方可以提供包含实现特定接口的类的JAR.使用URLClassLoader,我能够加载该类并实例化它,没问题.因为代码可能不受信任,我需要防止它行为不端.例如,我在一个单独的线程中运行插件代码,这样如果它进入无限循环或者只是花费太长时间我就可以杀死它.但是尝试为他们设置一个安全沙箱,以便他们无法做出像网络连接或访问硬盘驱动器上的文件这样的事情让我感到非常沮丧.我的努力总是导致对插件没有影响(它具有与应用程序相同的权限)或者也限制了应用程序.我希望主应用程序代码能够完成它想要的任何东西,
关于这一主题的文献和在线资源是复杂,混乱和矛盾的.我已经阅读过各种各样的地方(例如这个问题),我需要提供一个自定义的SecurityManager,但是当我尝试它时,我遇到了问题,因为JVM延迟加载JAR中的类.所以我可以很好地实例化它,但是如果我在加载的对象上调用一个方法来实例化来自同一个JAR的另一个类,那么它就会爆炸,因为它被拒绝了从JAR读取的权利.
从理论上讲,我可以在SecurityManager中检查FilePermission,看看它是否正在尝试加载自己的JAR.这没关系,但URLClassLoader文档说:"默认情况下,加载的类只被授予访问创建URLClassLoader时指定的URL的权限." 那为什么我甚至需要一个自定义的SecurityManager?URLClassLoader不应该只处理这个吗?为什么不呢?
这是一个重现问题的简化示例:
package test.app;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import test.api.Plugin;
public class PluginTest {
public static void pluginTest(String pathToJar) {
try {
File file = new File(pathToJar);
URL url = file.toURI().toURL();
URLClassLoader cl = new URLClassLoader(new java.net.URL[] { url });
Class<?> clazz = cl.loadClass("test.plugin.MyPlugin");
final Plugin plugin = (Plugin) clazz.newInstance();
PluginThread thread = new PluginThread(new Runnable() {
@Override
public void run() {
plugin.go();
}
}); …Run Code Online (Sandbox Code Playgroud) 好吧,所以说我有一个看起来像这样的课程:
public class SignupServlet extends HttpServlet {
private static final Logger SERVLET_LOGGER=COMPANYLog.open(SignupServlet.class);
private static final ExceptionMessageHandler handler = new ExceptionMessageHandler();
private static final SignupServletObservableAgent signupObservableAgent =
new SignupServletObservableAgent(null, SERVLET_LOGGER);
}
Run Code Online (Sandbox Code Playgroud)
我可以指望类加载器按顺序初始化这些字段,这样我可以依赖SERVLET_LOGGER在signupObservableAgent之前实例化吗?
在java中,据说所有类都是由类加载器加载的.
首先,bootstrap类加载器加载所有rt.jar类.
所以我仍然感到困惑,因为Classloader也是一个类,所以谁将加载这个BootStrapClassloader.
请解释一下.
我最近在工作中遇到过这个问题.虽然我不确定这是一个好主意,但我不明白编译器如何处理静态块.
这是一个例子:
考虑你有类A和B:
public class A {
public final static List<Integer> list;
static {
list = new ArrayList<>();
}
}
public class B {
public final static int dependsOnA;
static {
dependsOnA = A.list.size();
}
}
Run Code Online (Sandbox Code Playgroud)
还有一个只读的主要课程B.dependsOnA.
静态块B依赖于in A,因为它使用list静态变量.
现在,代码正确执行,并且NullPointerException在运行时不会引发.但是什么是确保list在其他地方潜在使用之前进行初始化的机制是什么?
我想知道是否以及如何在dalvik中动态加载dex或类文件,我写的一些quick'n'dirty测试函数是这样的:
public void testLoader() {
InputStream in;
int len;
byte[] data = new byte[2048];
try {
in = context.getAssets().open("f.dex");
len = in.read(data);
in.close();
DexFile d;
Class c = defineClass("net.webvm.FooImpl", data, 0, len);
Foo foo = (Foo)c.newInstance();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Run Code Online (Sandbox Code Playgroud)
而Foo界面就是这样
public interface Foo {
int get42();
}
Run Code Online (Sandbox Code Playgroud)
和f.dex包含该接口的一些dx'ed实现: …
我在应用服务器上运行了多个Web应用程序,每个Web应用程序WAR文件都包含相同jar文件的副本.
这是否意味着该jar文件中的一个类将在JVM中多次加载,对于它存在的每个WAR文件一次?接下来,如果我在这样的类中有一个静态同步方法,它是否只在它存在的web-app中的线程之间同步,而不是在不同jar文件中的同一个类中的同一方法同步WAR文件?(希望这个问题有道理,必要时会澄清).
如果是这种情况,我认为最好的解决方案是从每个WAR文件中删除jar文件并将其部署到服务器上的共享类路径文件夹中?
@CallerSensitive上述方法的注释隐含了什么?
例如,注释存在于Class的getClassLoader方法中
@CallerSensitive
public ClassLoader getClassLoader() {
//
}
Run Code Online (Sandbox Code Playgroud) 我还是比较新的Java,所以请耐心等待.
我的问题是我的Java应用程序依赖于两个库.让我们称它们为库1和库2.这两个库共享对库3的相互依赖.但是:
这正是JAR地狱的定义(或者至少是其中的一个变体).如链接中所述,我无法在同一个类加载器中加载第三个库的两个版本.因此,我一直试图弄清楚是否可以在应用程序中创建一个新的类加载器来解决这个问题.我一直在研究URLClassLoader,但我无法弄明白.
这是一个演示问题的示例应用程序结构.应用程序的Main类(Main.java)尝试实例化Library1和Library2,并运行在这些库中定义的一些方法:
Main.java(原始版本,在尝试解决方案之前):
public class Main {
public static void main(String[] args) {
Library1 lib1 = new Library1();
lib1.foo();
Library2 lib2 = new Library2();
lib2.bar();
}
}
Run Code Online (Sandbox Code Playgroud)
Library1和Library2都共享对Library3的相互依赖,但是Library1需要版本1,而Library2只需要版本2.在这个例子中,这两个库只打印他们看到的Library3版本:
Library1.java:
public class Library1 {
public void foo() {
Library3 lib3 = new Library3();
lib3.printVersion(); // Should print "This is version 1."
}
}
Run Code Online (Sandbox Code Playgroud)
Library2.java:
public class Library2 {
public void foo() {
Library3 lib3 = new Library3();
lib3.printVersion(); // Should print "This is …Run Code Online (Sandbox Code Playgroud)