问题描述:在SpringBoot项目中,需要用到JNI接口调用一段由 C++写的高性能模块,该模块在执行过程中,需要回调 Java 层的某个业务服务Bean,去注入这些业务Bean的时候报错,空指针注入失败。
原因分析:加载顺序问题。
JNI库加载时机:在 SpringBoot 应用启动时通过System.loadLibrary("xxx") 加载本地库,这个操作往往发生在main方法或某个@Configuration类的静态块中,一旦加载完成,C++代码就可能立即注册回调函数,并在后续被触发。
Spring Bean 的生命周期:Spring 容器是在 SpringApplication.run() 之后才开始初始化 Bean 的,
即使JNI接口本身被标记为 @Component,它的依赖注入也只会在 Spring 上下文完全启动后才完成。
所以,JNI 回调可能在 Spring 容器尚未完成 Bean 注入前就被 C++代码触发。此时,JNI实例虽然存在,但其依赖字段尚未被 Spring填充,导致null引用。
解决方案:利用静态变量 + @PostConstruct 延迟绑定
- 将业务Bean以静态变量的形式缓存
- 利用@PostConstruct 注解,在 Spring完成依赖注入后,将注入的实例赋值给静态变量
- 在 JNI 回调方法中,统一使用该静态变量
代码如下:
java
@Component
public class testProxy {
@Resource
private TestService testService;
private static TestService staticTestService;
@PostConstruct
public void init() {
staticTestService = testService;
}
public static void callbackEvent(String data) {
staticTestService.doSomething(data);
}
}