假设我有这段代码,它使用一些输入(例如 URL 路径)来通过反射来确定要运行的方法:
// init
map.put("/users/*", "viewUser");
map.put("/users", "userIndex");
// later
String methodName = map.get(path);
Method m = Handler.class.getMethod(methodName, ...);
m.invoke(handler, ...);
Run Code Online (Sandbox Code Playgroud)
这使用反射,因此可以提高性能。可以这样做:
// init
map.put("/users/*", new Runnable() { public void run() { handler.viewUser(); } });
map.put("/users", new Runnable() { public void run() { handler.userIndex(); } });
// later
Runnable action = map.get(path);
action.run();
Run Code Online (Sandbox Code Playgroud)
但手动创建所有这些Runnable都有其自身的问题。我想知道,我可以在运行时生成它们吗?因此,我将拥有第一个示例中的输入映射,并动态创建第二个示例的映射。当然,生成它只是构建一个字符串的问题,但是编译和加载它呢?
注意:我知道性能提升很小,这是过早优化的完美例子。因此,这是一个学术问题,我对运行时生成和代码编译感兴趣。
是否有任何工具可以连接到 jvm 并实时显示类如何加载到该 jvm 中?我想它会成为一个很棒的 jvisualvm 插件..但是没有找到这样的东西让我想知道这是否可行?我只找到了一些看似“晦涩”的工具的参考资料,这些工具与 weblogic 或 webspere 严格相关。
假设这样的工具是可能的,它是否与特定容器严格相关?
谢谢!
在我的库的代码中,我使用 JAXB 从 XML 文件加载类名,以便稍后使用Class.forName(). 一个虚构的例子来说明这一情况:
public void libraryMethod() throws Exception {
List<String> classNames = loadClassNamesFromXML();
for (String className : classNames) {
Class.forName(className).newInstance().doThings();
}
}
Run Code Online (Sandbox Code Playgroud)
现在,一些用户使用 OSGi 来配置他们的应用程序,他们使用与使用我的 XML 结构配置的类不同的类加载器来加载我的库。这意味着加载可能会失败,因为找不到该类。
有没有更可靠的方法来加载此类?或者还有其他方法来配置这些实例吗?我愿意接受导致此结果的建议:
public void libraryMethod() throws Exception {
// Spring does things like this:
List<SomeType> instances = loadInstancesFromXML();
for (SomeType instance : instances) {
instance.doThings();
}
}
Run Code Online (Sandbox Code Playgroud)
一些限制:
我想我在这里弄错了。
我有一个简单的servlet静态块,可以打印一些消息。据我了解,当 servlet 类首次加载到 jvm 中时,应该处理静态块。
我正在使用嵌入式jetty并使用 jvm 选项启动 jetty 服务器-verbose:class。
我可以在输出中看到该类在Servlet我第一次访问此 servlet 并查看消息之前很久就已加载。
但据我了解,静态块应该在类加载后立即初始化。我这里哪里错了?
我正在调试eclipse远程调试动态编译加载类时无法加载源代码的原因。我看到的论点-verbose:class是我的动态编译的类文件来自__JVM_DefineClass__. 我认为这意味着它们来自 JVM 堆空间本身,因为我让编译器将编译后的字节输出到“文件管理器”中,该文件管理器将编译后的字节缓存在内存中。
似乎调试时源代码可查看的唯一方法是,如果我在源代码查找路径中指定实际加载的类来自的位置...并且如果我指定该类所在的目录,则似乎不起作用正在编译类。我觉得如果我将编译的字节保存到磁盘,源加载可能会起作用。
那么,什么__JVM_DefineClass__意思呢?我的假设正确吗?
经过几个小时的斗争后,我开始感到非常沮丧。
我有一个 JKS 服务器文件,我想从 jar 中加载它。只要文件在 Jar 之外,使用 FileInputStream 就可以了,但是一旦我尝试将其更改为 getResourceAsStream,它就不会接受它,并说(没有这样的文件或目录)。
这就是项目的分发方式
ProjectFolder
-src
--package.name
---JKS File
---Class calling the resource retrieval and loading into the keystore
Run Code Online (Sandbox Code Playgroud)
我想我已经尝试了几乎所有我能想到的 this.getClass().getClassLoader().getResourceAsStream("jksFile.jks") 组合。
我提前为没有更具体地说明代码而道歉,但我实际上已经忘记了我尝试过什么和没有尝试过什么。
帮助!
提前致谢
我正在 Apache Spark 中以本地模式运行一个作业,该作业会将其结果保存到 s3a 文件系统。由于 Hadoop 2.6 没有 s3a:// 实现(或 s3://、s3n://)。我打包了一个 uber jar,其中包含 hadoop-aws 2.6.0 的所有传递依赖项,并将其与我的主要工作的 jar 一起提交。
但是,当我使用以下简约代码对其进行测试时:
sc.parallelize(1 to 100).saveAsTextFile("s3a://***/test10/")
Run Code Online (Sandbox Code Playgroud)
编译器在第一次运行时给了我这个错误:
java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
at com.amazonaws.auth.AWSCredentialsProviderChain.<clinit>(AWSCredentialsProviderChain.java:41)
at org.apache.hadoop.fs.s3a.S3AFileSystem.initialize(S3AFileSystem.java:112)
at org.apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.java:2596)
at org.apache.hadoop.fs.FileSystem.access$200(FileSystem.java:91)
at org.apache.hadoop.fs.FileSystem$Cache.getInternal(FileSystem.java:2630)
at org.apache.hadoop.fs.FileSystem$Cache.get(FileSystem.java:2612)
at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:370)
at org.apache.hadoop.fs.Path.getFileSystem(Path.java:296)
at org.apache.spark.SparkHadoopWriter$.createPathFromString(SparkHadoopWriter.scala:170)
at org.apache.spark.rdd.PairRDDFunctions.saveAsHadoopFile(PairRDDFunctions.scala:953)
at org.apache.spark.rdd.PairRDDFunctions.saveAsHadoopFile(PairRDDFunctions.scala:863)
at org.apache.spark.rdd.RDD.saveAsTextFile(RDD.scala:1290)
Run Code Online (Sandbox Code Playgroud)
如果我尝试再次运行,则会出现以下错误:
java.lang.NoClassDefFoundError: Could not initialize class com.amazonaws.auth.AWSCredentialsProviderChain
at org.apache.hadoop.fs.s3a.S3AFileSystem.initialize(S3AFileSystem.java:112)
at org.apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.java:2596)
at org.apache.hadoop.fs.FileSystem.access$200(FileSystem.java:91)
at org.apache.hadoop.fs.FileSystem$Cache.getInternal(FileSystem.java:2630)
at org.apache.hadoop.fs.FileSystem$Cache.get(FileSystem.java:2612)
at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:370)
at org.apache.hadoop.fs.Path.getFileSystem(Path.java:296)
at org.apache.spark.SparkHadoopWriter$.createPathFromString(SparkHadoopWriter.scala:170)
at org.apache.spark.rdd.PairRDDFunctions.saveAsHadoopFile(PairRDDFunctions.scala:953)
at org.apache.spark.rdd.PairRDDFunctions.saveAsHadoopFile(PairRDDFunctions.scala:863)
at org.apache.spark.rdd.RDD.saveAsTextFile(RDD.scala:1290)
Run Code Online (Sandbox Code Playgroud)
奇怪的是:LogFactory …
我创建了一个库,它将 jar 直接加载到当前类路径中以启动其类之一。但注入的 jar 包含证书,所以我收到此错误:
java.lang.SecurityException: class "TestClass" signer information does not match signer information of other classes in the same package
Run Code Online (Sandbox Code Playgroud)
这很正常,但我无法摆脱它。这是正常的,因为两个不同的 jar 正在“冲突”,但是,我无法删除 JAR 的证书,因为它是第三方的。
那么,我可以禁用类证书检查吗?或者做一些事情来消除这个错误?
我想我需要覆盖该ClassLoader.checkCerts方法......但这很脏......
在 Java 中,可以使用以下方法替换默认系统 ClassLoader:
java -Djava.system.class.loader=com.test.MyClassLoader xxx
Run Code Online (Sandbox Code Playgroud)
这样,自定义类加载器用于加载新类,同时将默认系统类加载器作为其父类。
可以使用非运行时方法在 Android 应用程序中完成相同的系统 ClassLoader 替换吗?(gradle/manifest 或其他一些编译标志)
我不想在运行时替换系统类加载器,而是在整个应用程序启动时为整个应用程序设置一个不同的系统类加载器,甚至在应用程序类加载之前。
最终目标是在<clinit>调用Application 类之前运行代码(这基本上允许我按照我认为合适的方式加载应用程序中的所有类)。
在这样的模块结构中:
项目
|
|- 通用模块
|- 应用模块
在 app 模块具有公共模块作为依赖项的情况下,我在公共模块中定义了一个自定义类加载器类。app 模块有一个-Djava.system.class.loader=org.project.common.CustomClassLoaderjvm 参数集来使用公共模块中定义的自定义类加载器。
在 IDEA 中运行一个 spring boot 项目,这非常有效。找到自定义类加载器,设置为系统类加载器,一切正常。
编译一个可运行的 jar(使用没有任何自定义属性的默认 spring-boot-maven-plugin),jar 本身包含所有类,并且在它的 lib 目录中是具有自定义类加载器的公共 jar。但是运行 jar 的-Djava.system.class.loader=org.project.common.CustomClassLoader结果是以下异常
java.lang.Error: org.project.common.CustomClassLoader
at java.lang.ClassLoader.initSystemClassLoader(java.base@12.0.2/ClassLoader.java:1989)
at java.lang.System.initPhase3(java.base@12.0.2/System.java:2132)
Caused by: java.lang.ClassNotFoundException: org.project.common.CustomClassLoader
at jdk.internal.loader.BuiltinClassLoader.loadClass(java.base@12.0.2/BuiltinClassLoader.java:583)
at jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(java.base@12.0.2/ClassLoaders.java:178)
at java.lang.ClassLoader.loadClass(java.base@12.0.2/ClassLoader.java:521)
at java.lang.Class.forName0(java.base@12.0.2/Native Method)
at java.lang.Class.forName(java.base@12.0.2/Class.java:415)
at java.lang.ClassLoader.initSystemClassLoader(java.base@12.0.2/ClassLoader.java:1975)
at java.lang.System.initPhase3(java.base@12.0.2/System.java:2132)
Run Code Online (Sandbox Code Playgroud)
为什么会发生这种情况?是因为在可运行的 jar 中,类加载器类位于 lib 目录中的 jar 中,因此类加载器试图在将 lib 类添加到类路径之前进行设置?除了将类加载器从 common 移动到所有其他需要它的模块之外,我还能做些什么吗?
编辑:我尝试将自定义类加载器类从通用模块移动到应用程序,但我仍然遇到相同的错误。这里发生了什么?
classloader ×10
java ×8
jvm ×3
android ×1
apache-spark ×1
eclipse ×1
javac ×1
loading ×1
osgi ×1
scala ×1
servlets ×1
spring ×1
spring-boot ×1
system ×1