我正在尝试在Intellij 的JUnit测试ClassLoader.getResourceAsStream中使用加载资源,但如果该资源位于子文件夹中,则找不到该资源。它可以在测试资源文件夹的根目录中找到。我正在使用正确的用斜杠替换点符号。-
这与这里提出的问题不同,因为我意识到我在资源路径的开头添加了斜杠。
使用 CustomClassloader 或 Java 代理 + Instrumentation API 都可以非常简单直接地获取 JVM 已加载的所有类。然而,已经初始化的类列表似乎并不那么容易获取。(其实我想知道有没有什么办法可以得到)
那么,有没有办法知道一个类是否已经初始化了呢?
- 提前致谢
从资源文件夹加载文本文件等资源时,最常见的方法是使用 ClassLoader 获取路径:
String path = getClass().getClassLoader().getResource("file.txt").getPath();
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用 java 具有的众多读取器中的任何一个来读取该文件的内容。但由于某种原因,Paths.get(path)对这条路不满意:
byte[] content = Files.readAllBytes(Paths.get(path))
-> throws java.nio.file.InvalidPathException when executed
Run Code Online (Sandbox Code Playgroud)
ClassLoader.getResource(...).getPath() 正在返回:
/D:/Projects/myapp/build/resources/main/file.txt
Run Code Online (Sandbox Code Playgroud)
Paths.get()不喜欢它。显然后面的“:”/D是“非法字符”。(注意,路径看起来是正确的,文件实际上在那里)
哪一个导致了问题?是ClassLoader.getResource()返回无效路径还是Paths.get()无故行为?
一段时间后
,java中的路径似乎有多种不同的格式。各种框架似乎并不完全同意什么是正确的,什么是错误的,因此它们创建和接受的路径之间存在各种差异。
在此示例中,Paths.get()实际上并不期望路径中存在前导斜杠:
/D:/Projects/myapp/build/resources/main/vertex.vs.glsl <- EVIL
D:/Projects/myapp/build/resources/main/vertex.vs.glsl <- OK
Run Code Online (Sandbox Code Playgroud)
我想现在的问题是:如何清理返回的文件路径ClassLoader.getResource()以正确使用Paths.get()?这两种文件路径格式之间还有其他区别吗?
如何在 Spring Boot 中使用自定义类加载器加载 bean
\n\n我需要加密 Spring Boot 项目。
\n\n起初我尝试使用proguard,但失败了,因为 spring 使用大量 Annotations 并且它有DI。
\n\n然后我尝试使用自定义类加载器。我想先加密我的类文件,然后使用我的自定义类加载器加载加密的类文件,然后解密它\xe3\x80\x82
\n\n这是我的演示: https: //github.com/CaiBaohong/boot-by-custom-loader
\n\n启动时失败:
\n\nConfigServletWebServerApplicationContext : \n Exception encountered during context initialization - cancelling refresh attempt: \n org.springframework.beans.factory.UnsatisfiedDependencyException: \n Error creating bean with name \'methodValidationPostProcessor\' defined in class path resource \n [org/springframework/boot/autoconfigure/validation/ValidationAutoConfiguration.class]: \n Unsatisfied dependency expressed through method \'methodValidationPostProcessor\' parameter 0; \n nested exception is \n org.springframework.beans.factory.CannotLoadBeanClassException: \n Error loading class [com.abc.bootbycustomloader.controller.UserController] \n …Run Code Online (Sandbox Code Playgroud) 我正在 Docker 映像中运行 Java 服务,其执行如下操作:
java -server -cp 'libs/*'
奇怪的是,我发现它会在我的本地计算机上启动,但不会在开发服务器上启动,在开发服务器上它会给出NoSuchMethodError.
经过一番挖掘,我发现 libs 目录中同时存在 JPA 2.0 和 2.1 版本。虽然这本身就是一个问题(并且很容易修复),但它并不能解释不一致的原因,所以我决定打印出来:
(ClassLoader.getSystemClassLoader() as URLClassLoader).urLs
.forEach(::println) // kotlin
Run Code Online (Sandbox Code Playgroud)
我发现两台机器上的库顺序不同。然而,在同一台机器上后续运行的图像之间是一致的,所以不是随机的。
虽然我现在知道为什么镜像无法在开发服务器上启动,并且我可以解决手头的问题,但它确实让我想知道:为什么这个顺序在 Docker 主机上不一致?可复现性和一致性不正是Docker的要点之一吗?类路径的顺序是否取决于 IP、主机名或安装的主机目录(在不相关的位置)等挑剔的事物?
我想用jdk.internal.loader.ClassLoaders$AppClassLoaderspring-boots 代替org.springframework.boot.loader.LaunchedURLClassLoader。但是,我不确定这将如何影响 spring-boot 运行时。
我们最近在java.lang.InstantiationErrorjava 的parallelStream(). 我了解到并行流中的线程正在使用AppClassLoader,因此无法找到驻留在类加载器层次结构中LaunchedURLClassLoader的子级中的应用程序类AppClassLoader。
spring -boot 文档显示您可以在不使用类加载器的情况下运行解压的 spring-boot jar。这很方便地意味着应用程序类也被加载到 中AppClassLoader,从而解决了我们的问题parallelStream()。
$ java -cp BOOT-INF/classes:BOOT-INF/lib/* com.example.MyApplication
Run Code Online (Sandbox Code Playgroud)
注意:这也是 Intellij IDEA 运行 spring-boot 应用程序的方式。
谁知道 spring-boot 类加载器是否所做的不仅仅是启用我应该了解的可执行 jar 和 war 文件。我发现文档不够明确。在生产中不使用 spring-boot 类加载器是否安全?
我之前已经看过这里,了解如何将 jar 动态加载到类路径中。当时提出的这个解决方案完美无缺:
File file = ...
URL url = file.toURI().toURL();
URLClassLoader classLoader = (URLClassLoader)ClassLoader.getSystemClassLoader();
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(classLoader, URL);
Run Code Online (Sandbox Code Playgroud)
然而,这在 Java 9+ 中是不可能的,但有一个涉及Module#addOpens的 hack ,它允许打开 URL 方法。例如,打开模块的代码如下所示:
try {
final Class<?> moduleClass = Class.forName("java.lang.Module");
final Method getModuleMethod = Class.class.getMethod("getModule");
final Method addOpensMethod = moduleClass.getMethod("addOpens", String.class, moduleClass);
final Object urlClassLoaderModule = getModuleMethod.invoke(URLClassLoader.class);
final Object thisModule = getModuleMethod.invoke(DependencyUtilities.class);
addOpensMethod.invoke(
urlClassLoaderModule, URLClassLoader.class.getPackage().getName(), thisModule);
Logger.info(
"User is using Java 9+, meaning Reflection Module does have to …Run Code Online (Sandbox Code Playgroud) 我有一个源自Maven 入门项目的Flink 作业。该作业有一个打开 Postgres JDBC 连接的源。我正在使用示例docker-compose.yml在我自己的 Flink 会话集群上执行该作业。
当我第一次提交作业时,它执行成功。当我尝试再次提交时,出现以下错误:
Caused by: java.sql.SQLException: No suitable driver found for jdbc:postgresql://host.docker.internal:5432/postgres?user=postgres&password=mypassword
at java.sql.DriverManager.getConnection(DriverManager.java:689)
at java.sql.DriverManager.getConnection(DriverManager.java:270)
at com.myorg.project.JdbcPollingSource.run(JdbcPollingSource.java:25)
at org.apache.flink.streaming.api.operators.StreamSource.run(StreamSource.java:110)
at org.apache.flink.streaming.api.operators.StreamSource.run(StreamSource.java:66)
at org.apache.flink.streaming.runtime.tasks.SourceStreamTask$LegacySourceFunctionThread.run(SourceStreamTask.java:269)
Run Code Online (Sandbox Code Playgroud)
我必须重新启动集群才能重新运行我的作业。为什么会发生这种情况?如何在不重启集群的情况下再次提交作业?
Maven 入门项目的唯一补充是:
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.24</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)
Flink 源代码除了打开 JDBC 连接之外什么也不做,如下所示:
package com.mycompany;
import org.apache.flink.streaming.api.functions.source.RichSourceFunction;
import java.sql.Connection;
import java.sql.DriverManager;
public class JdbcSource extends RichSourceFunction<Integer> {
private final String connString;
public JdbcSource(String connString) {
this.connString = connString;
}
@Override
public void run(SourceContext<Integer> ctx) throws Exception …Run Code Online (Sandbox Code Playgroud) 我正在使用 Java 代理 (Agent.class) 以包含对 Agent 类的调用的方式转换程序 (Program.class) 中的方法。
public Program.getMultiplier()F:
ALOAD 1
ALOAD 2
FDIV
+ INVOKESTATIC Agent.getCustomMultiplier(F)F
FRETURN
Run Code Online (Sandbox Code Playgroud)
我检查了代理类和程序类的类加载器及其父类,它们的层次结构如下所示:
AppClassLoader<- PlatformClassLoader<-nullURLClassLoader<- PlatformClassLoader<-null当程序执行添加的INVOKESTATIC指令时,它会抛出 ClassNotFoundException - 它无法找到 Agent 类,因为它是由不同的类加载器加载的。
作为临时解决方案,我尝试强制AppClassLoader成为URLClassLoaderwith 反射的父级,它适用于较旧的 Java 版本,但自 Java 12 以来已被删除。
有没有更可靠的方法来确保我的代理类在任何类加载器中都是可见的?
我正在使用 RMI 调用指定返回 class 对象的方法ClassX。
ClassX xObj = remoteObject.meth(...);
Run Code Online (Sandbox Code Playgroud)
SubclassOfX如果远程方法实际上返回 的本地未知子类的实例ClassX,则该类SubclassOfX会自动从 a 下载codebase(由 的序列化实例上的注释指定SubclassOfX)。
(对于那些需要它的人:RMI 中的代码库概念)
在 Java17 之前,必须使用 SecurityManager(和策略文件)来允许从代码库加载类。但从 Java17 开始,SecurityManager 已被弃用并标记为删除。
我现在的问题是:将来如何允许/控制从代码库加载类?
Edit1:只是为了回答引用 jep411 的评论:我知道这个文档,但其中没有针对 SecurityManager 的 RMI 用例给出解决方案/替代方案。
classloader ×10
java ×9
jvm ×2
spring-boot ×2
apache-flink ×1
classloading ×1
classpath ×1
dependencies ×1
docker ×1
encryption ×1
jar ×1
javaagents ×1
junit ×1
obfuscation ×1
path ×1
rmi ×1
runtime ×1
spring ×1
subdirectory ×1