我刚刚开始学习Java的内部架构.我已经粗略地理解了类加载的概念,它在jvm运行时加载所需的类,ClassNotFoundException在没有找到类时抛出,特定的类加载器加载类引用的类.
有人可以清楚地解释类加载的流程,即下面的示例Java代码中的引导类加载和用户定义的类加载的顺序.
import java.io.File;
public class Sample
{
public static void main(String[] args)
{
String fileName = "sample";
File file = new File(fileName);
file.isFile();
}
}
Run Code Online (Sandbox Code Playgroud)
我还从一个参考资料中学到了" classloader维护它加载的类的名称空间".通过名称空间,这是否意味着类的文字名称?也有人可以解释一下这个含义/优点吗?
如果我使用
try {
Class.forName("my.package.Foo");
// it exists on the classpath
} catch(ClassNotFoundException e) {
// it does not exist on the classpath
}
Run Code Online (Sandbox Code Playgroud)
"Foo"的静态初始化程序块启动.有没有办法确定类"my.package.Foo"是否在类路径上而没有启动其静态初始化程序?
我开发了一个基于XML的大量Java应用程序,最近在Ubuntu Linux上遇到了一个有趣的问题.
我的应用程序使用Java插件框架,似乎无法将dom4j创建的XML文档转换为Batik的 SVG规范实现.
在控制台上,我了解到发生了错误:
Exception in thread "AWT-EventQueue-0" java.lang.LinkageError: loader constraint violation in interface itable initialization: when resolving method "org.apache.batik.dom.svg.SVGOMDocument.createAttribute(Ljava/lang/String;)Lorg/w3c/dom/Attr;" the class loader (instance of org/java/plugin/standard/StandardPluginClassLoader) of the current class, org/apache/batik/dom/svg/SVGOMDocument, and the class loader (instance of <bootloader>) for interface org/w3c/dom/Document have different Class objects for the type org/w3c/dom/Attr used in the signature
at org.apache.batik.dom.svg.SVGDOMImplementation.createDocument(SVGDOMImplementation.java:149)
at org.dom4j.io.DOMWriter.createDomDocument(DOMWriter.java:361)
at org.dom4j.io.DOMWriter.write(DOMWriter.java:138)
我认为问题是由JVM的原始类加载器与插件框架部署的类加载器之间的冲突引起的.
据我所知,不可能为框架指定要使用的类加载器.它可能是破解它,但我宁愿采用一种不那么积极的方法来解决这个问题,因为(无论出于什么原因)它只发生在Linux系统上.
你们其中一个遇到过这样的问题,并且知道如何解决这个问题或至少解决问题的核心问题?
当我的网络应用程序所依赖的其中一个罐试图从jar中加载属性文件时,我遇到了麻烦.这是jar中的代码.
static
{
Properties props = new Properties();
try
{
props.load(ClassLoader.getSystemResourceAsStream("someProps.properties"));
} catch (IOException e)
{
e.printStackTrace();
}
someProperty = props.getProperty("someKey");
}
Run Code Online (Sandbox Code Playgroud)
属性文件位于Maven项目的"src/main/resources"目录中.当我在Eclipse中的junit测试中运行此代码时,它执行得很好.当项目使用Maven构建到jar中,并作为依赖项包含在我的Web应用程序中时,它无法找到属性文件.我知道属性文件位于依赖于jar的基本目录中,我不知道如何解决这个问题.
我在eclipse helios中创建了一个带有单个子模块的最小maven项目.
在src/test/resources文件夹中,我放了一个文件"install.xml".在文件夹src/test/java中,我创建了一个包含单个类的包:
@Test
public void doit() throws Exception {
URL url = this.getClass().getClassLoader().getResource("install.xml");
System.out.println(url.getPath());
}
Run Code Online (Sandbox Code Playgroud)
但是当我将代码作为junit 4单元测试运行时,我只得到一个NullPointerException.这之前已经运行了数百万次.有任何想法吗?
我遵循了这个指南:
http://www.fuyun.org/2009/11/how-to-read-input-files-in-maven-junit/
但仍然得到相同的错误.
我试图列出Java类加载器加载我的类的顺序.如果我使用-verbose的参数将列出每一个接口/类加载,包括吨,如序列化接口,异常等是否有办法来调整这个输出,因此只有这些类是在类加载显示我的主要方法是定义?
我正在使用一些第三方代码,当给出'-classpath'命令行参数时,不设置java.class.path,而只是创建一个类加载器,将命令行指定类路径上的项的所有url添加到类加载器,然后将其设置为上下文类加载器.在我编写的这段代码的插件类中,我得到了这个类加载器的一个实例,并且不知何故需要使用它来获取底层的类路径,以便我可以在JavaCompiler.getTask的调用中使用它(... )并动态编译其他代码.但是,似乎没有从ClassLoader获取ClassPath,并且由于java.class.path未设置,我似乎无法访问最初调用应用程序的基础类路径...任何想法?
从我们的发行说明了解到的Java 9是
应用程序类加载器不再是java.net.URLClassLoader的实例(在以前的版本中从未指定过的实现细节).假定ClassLoader :: getSytemClassLoader返回URLClassLoader对象的代码需要更新.
这会破坏旧代码,它会扫描类路径,如下所示:
Java <= 8
URL[] ressources = ((URLClassLoader) classLoader).getURLs();
Run Code Online (Sandbox Code Playgroud)
哪个遇到了
java.lang.ClassCastException:
java.base/jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to
java.base/java.net.URLClassLoader
Run Code Online (Sandbox Code Playgroud)
因此,对于Java 9+,以下解决方法被提议作为Apache Ignite项目的PR,它在JVM运行时选项中进行调整时可以正常工作:--add-opens java.base/jdk.internal.loader=ALL-UNNAMED.但是,如下面的评论所述,这个PR从未合并到他们的主分支.
/*
* Java 9 + Bridge to obtain URLs from classpath...
*/
private static URL[] getURLs(ClassLoader classLoader) {
URL[] urls = new URL[0];
try {
//see https://github.com/apache/ignite/pull/2970
Class builtinClazzLoader = Class.forName("jdk.internal.loader.BuiltinClassLoader");
if (builtinClazzLoader != null) {
Field ucpField = builtinClazzLoader.getDeclaredField("ucp");
ucpField.setAccessible(true);
Object ucpObject = …Run Code Online (Sandbox Code Playgroud) 我在其他地方找不到这个问题的明确答案,所以我会在这里试试:
是否有某种方式(编程或其他方式)以按照它们加载的精确顺序获取由Application Classloader加载的JAR /类列表?应用程序类加载器我的意思是在应用程序服务器(WLS,WAS,JBoss ......)中加载EAR应用程序的类加载器,但显然,它适用于任何类加载器.
因此,为了概括,我想知道的是由指定的类加载器加载的JAR的列表和顺序.不是单个类,通过调用classloader.getPackages()很容易找到,但是这个类加载器加载的JAR文件列表.
我们正在创建多个子类加载器,以将多个子应用程序加载到Java应用程序"容器"中,进行热部署原型设计.当特定类加载器的类路径发生更改(即已添加,删除,更新了jar)时,旧的类加载器将被丢弃(未引用),并为新的jar类路径创建新的类加载器.
更新类路径,触发热部署后,我们进行了堆转储.堆转储(使用Memory Analyzer)表明旧的类加载器没有被垃圾回收.父类加载器中的某些类正在缓存旧的类加载器.调用以下内容来清除这些缓存:
java.lang.ResourceBundle.clearCache(classLoader);
org.apache.commons.logging.LogFactory.release(classLoader);
java.beans.Introspector.flushCaches();
Run Code Online (Sandbox Code Playgroud)
即使在清除了上述缓存之后,旧的类加载器仍然没有被垃圾收集.对类加载器的其余引用包括以下内容:
以上所有都是类加载器中的循环引用,它应该触发垃圾回收.我不确定为什么不是.有没有人知道为什么旧的类加载器仍然没有被垃圾收集,即使有循环引用?
classloader ×10
java ×9
maven-2 ×2
class ×1
eclipse ×1
jar ×1
java-9 ×1
jvm ×1
linkageerror ×1
linux ×1
memory-leaks ×1
properties ×1
resources ×1