我试图从Java服务提供者(META-INF/services)的静态代码中访问Spring Boot ApplicationContext中实例化的bean。我使用的是Java14(openjdk:14JDKslim)。
在远程调试器会话中,我可以看到应用程序上下文CONTEXT
的静态变量被设置为正确的值:
@Component
@Slf4j
public class ApplicationContextListener implements ApplicationContextAware {
private static volatile ApplicationContext CONTEXT;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
CONTEXT = applicationContext;
}
...
下次在运行时(从另一个线程)访问它时,变量CONTEXT
为空,例如:
public static MyBean getMyBean() {
return CONTEXT.getBean(MyBean.class);
}
我怀疑问题在于持有静态变量的类在这两者之间“卸载”。但是1)为什么在应用程序上下文中定义有效bean的类会发生这种情况2)如何避免这种情况?
在应用程序执行期间,静态变量稍后变为null的原因是什么?除了上面列出的变量外,没有设置变量的代码。setApplicationContext
仅被调用一次。
如果问题与类卸载有关,我如何避免?
也许我的初始化代码是针对类加载器a加载的类中的静态变量执行的,而对类加载器B加载的同一类中未初始化的静态变量进行访问?假设这就是原因,我如何解决这个问题?
非常感谢。
使现代化
当在方法setApplicationContext
中时,类ApplicationContextListener
实例的类加载器是org。springframework。靴子开发工具。重新启动。类加载器。重新启动ClassLoader
,此操作返回。getClass()。getClassLoader()。
当调试器稍后在ApplicationContextListener
class静态方法中停止时,调试器将为ApplicationContextListener显示
ClassLoaders$AppClassLoader
。班getClassLoader()
在后一种情况下(在静态get中),Thread.currentThread(). getContextClassLoader()也显示了org.springframework.boot.devtools.restart.classloader.RestartClassLoader。
原因是Spring Boot自动重启功能在默认情况下通过依赖于我用来创建项目的Spring初始值设定项添加的Spring Bootdevtools
而启用。
该特性允许通过额外的类加载器加载bean类。
在这种情况下,访问静态变量的一种方法如下:
private static ApplicationContext getContext() {
try {
return (ApplicationContext) getClass(ApplicationListenerContext.class.getName())
.getField("CONTEXT").get(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static Class getClass(String classname) throws ClassNotFoundException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if(classLoader == null) {
classLoader = ApplicationListenerContext.class.getClassLoader();
}
return classLoader.loadClass(classname);
}
另一方面,实际上并不需要这种变通办法。通过传递-Dspring可以关闭自动重启功能。开发工具。重新启动。应用程序启动参数的enabled=false
。
更简单的解决方案是从我打包到服务Docker映像中的分解库中排除sping-boo-devols
依赖关系:
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<excludeArtifactIds>spring-boot-devtools</excludeArtifactIds>
</configuration>
</execution>
</executions>
</plugin>
以下问题提供了有关此主题的更多详细信息:
类加载器错误-加载器组织的未命名模块。springframework。靴子开发工具。重新启动。类加载器。重新启动ClassLoader
什么是NoSuchBean定义异常以及如何修复它?
问题内容: 我想知道为什么默认情况下C,C ++和Java中的确切静态变量初始化为零?为什么对局部变量不是这样? 问题答案: 为什么要对静态变量进行确定性初始化而对局部变量不进行初始化? 了解如何实现静态变量。 它们的内存在链接时分配,并且它们的初始值也在链接时提供。 没有运行时开销。 另一方面,用于局部变量的内存是在运行时分配的。堆栈必须增长。你不知道以前在那里。如果需要,可以清除该内存(将其清
问题内容: 如何在Java中初始化类的私有静态成员。 尝试以下操作: 但是在创建类A的第二个对象然后调用f1()时,我得到了空指针异常。 问题答案: 初始化静态成员的首选方法是(如上所述) 或者对于更复杂的初始化代码,您可以使用静态初始化程序块:
我正在开发我的第一个 Swing 应用程序,现在提出了一个难题:在静态初始化期间或开始实际执行后执行引导和资源初始化。我是什么意思...我有单例: 因此,方法如下所示 或者,也许我在启动后手动初始化资源,然后运行它。逻辑上正确的方式是什么?
问题内容: 当我运行此代码时,答案是1,我想应该是2。初始化的顺序和每一步中k的值是什么? 编辑1:作为后续的“ k设置为默认值”,那么为什么下一个代码不能编译?出现错误“在定义字段之前无法引用它”。 编辑2:出于某种我不知道的原因,它^可以在其“ Test.k”代替“ k”时使用。 感谢所有的答案。这将满足:D 问题答案: 它们按照您编写它们的顺序执行。如果代码是: 然后输出变为2。 初始化的顺
问题内容: 我有以下代码: 这给了我以下错误: 解析错误:语法错误,在第19行的/home/user/Sites/site/registration/inc/registration.class.inc中出现意外的’(’,期待’)’ 所以,我想我做错了什么…但是如果不那样做怎么办?如果我用常规字符串更改mktime内容,它将起作用。所以,我知道我能做到这一点 的那种 像.. 有人有指针吗? 问题答
问题内容: 我想知道静态变量何时初始化为其默认值。加载类时,先创建(分配)静态变量,然后执行静态初始化程序和声明中的初始化是否正确?在什么时候给出默认值?这导致前向参考的问题。 另外,如果你可以参考“ 为什么没有及时初始化静态字段?”这一问题进行解释,尤其是Kevin Brock在同一网站上给出的答案。我不明白第三点。 问题答案: 从请参阅Java静态变量方法: 它是一个属于类而不属于对象(实例)