Eclipse插件依赖注入报错:无法获取实例及空指针问题
Eclipse插件DI与OSGi启动问题解答
核心原因总结
你遇到的两个异常,本质都是Bundle Activator/IApplication的启动时机早于DI容器初始化导致的:
- 你给
Application加@Singleton后,它的实例是由OSGi框架/Eclipse平台直接创建的,不属于DI容器管理对象,因此其他类无法通过@Inject获取它; ContextHolder作为DI管理的单例,在Application.start()执行时还未被DI容器实例化,自然会出现空指针。
1. DI在Bundle Activator/IApplication启动时的可用性
明确结论:是的,DI容器在Bundle Activator的start()、IApplication的start()执行阶段尚未完成初始化。
这些启动类是由OSGi框架或Eclipse平台直接实例化调用的,不属于DI容器的管理范畴,此时依赖注入逻辑还未生效,无法通过注解获取实例。
2. 声明式注入OSGi服务的正确方式
根据你使用的DI体系,分两种常见场景:
基于OSGi Declarative Services(DS)
- 消费服务的类需标记为DS组件:添加
@Component注解; - 用
@Reference注入OSGi服务,示例:@Component public class ModelTreeContentProvider { @Reference private Inez inezService; // 组件激活时触发,此时服务已注入 @Activate void init() { // 初始化逻辑 } } - 确保bundle的
MANIFEST.MF中配置Service-Component: OSGI-INF/components.xml(该文件可由注解处理器自动生成)。
基于Eclipse 4 RCP的Context Injection
- 若为E4容器管理的对象(如Part、Handler),直接用
@Inject+@OSGiService注入:public class ModelTreeContentProvider { @Inject @OSGiService private Inez inezService; } - 非E4管理的类,需通过
ContextInjectionFactory手动获取实例,确保DI生效。
3. 声明非OSGi服务的可注入类
自定义的非OSGi类要被DI容器管理,需按以下方式声明:
OSGi DS方式
- 给类添加
@Component注解,若无需注册为OSGi服务,可指定service = false;若需被其他组件引用,指定服务接口:@Component(service = ContextHolder.class) @Singleton public class ContextHolder { private Application app; public void setApplication(Application app) { this.app = app; } } - 其他组件通过
@Reference注入该类实例。
E4 DI方式
- 给类添加
@Singleton+@Creatable注解,使其纳入E4容器管理:@Singleton @Creatable public class ContextHolder { // 自定义逻辑 } - 其他E4管理类直接用
@Inject注入即可。
针对你遇到的异常的修复方案
1. 解决Application注入失败问题
Application是平台创建的实例,需手动将其纳入DI上下文:
- 若用E4 DI,在
Application.start()中添加:@Override public Object start(IApplicationContext appContext) throws Exception { IEclipseContext eclipseContext = EclipseContextFactory.getServiceContext(appContext.getBundleContext()); // 将当前Application实例放入DI上下文 eclipseContext.set(Application.class, this); return IApplicationContext.EXIT_OK; } - 之后
ModelTreeContentProvider即可通过@Inject获取Application实例。
2. 解决ContextHolder空指针问题
不要在Application.start()中直接调用未初始化的ContextHolder,可改为:
- 用OSGi
ServiceTracker等待ContextHolder激活后再操作:@Override public void start(BundleContext bundleContext) throws Exception { // 注册Application为OSGi服务(可选,方便其他组件获取) bundleContext.registerService(Application.class, this, null); // 等待ContextHolder组件激活 ServiceTracker<ContextHolder, ContextHolder> tracker = new ServiceTracker<>(bundleContext, ContextHolder.class, null); tracker.open(); ContextHolder contextHolder = tracker.waitForService(1000); // 超时时间按需调整 if (contextHolder != null) { contextHolder.setApplication(this); } }
内容的提问来源于stack exchange,提问作者Árpád Magosányi
相关产品推荐
相关产品推荐

