如何在非OSGi服务类中注入OSGi服务?
我来分享几个在非OSGi服务类中注入服务的实用方案,刚好我之前在OSGi开发中也碰到过类似场景——服务类需要创建非服务实例,而后者又依赖OSGi服务来完成业务逻辑:
方案1:通过服务类传递依赖(最推荐、最简洁)
你的MessageBusListener本身已经绑定了QueueExecutor等OSGi服务,那在创建FlowListener时,直接把它需要的流程调用类服务传递过去就好,完全不需要接触OSGi容器的底层API:
// MessageBusListener(已注册的OSGi服务类) public class MessageBusListener implements MessageBusListenerService { // 已通过OSGi绑定的流程调用服务 private ProcessInvocationService processInvocationService; // 其他已绑定服务(比如QueueExecutor)... // OSGi服务绑定方法(可通过@Reference注解或XML配置实现) public void setProcessInvocationService(ProcessInvocationService service) { this.processInvocationService = service; } // 创建FlowListener的逻辑 public FlowListener createFlowListener() { // 直接把依赖注入到非服务类的构造器中 return new FlowListener(processInvocationService); } } // 非服务类FlowListener public class FlowListener { private final ProcessInvocationService processService; // 通过构造器接收依赖,保证实例创建时依赖已就绪 public FlowListener(ProcessInvocationService processService) { this.processService = processService; } // 处理消息时调用OSGi服务 public void handleMessage(Message msg) { processService.invokeFlow(msg.getFlowId(), msg.getPayload()); } }
这种方式完全遵循依赖注入的思想,耦合度极低,还能避免非服务类直接和OSGi容器绑定,是最优解。
方案2:借助BundleContext动态获取服务
如果FlowListener需要的服务没办法直接从MessageBusListener传递(比如依赖服务多、需要动态切换),可以让MessageBusListener把自身的BundleContext传给FlowListener,后者通过上下文获取服务:
// MessageBusListener中注入BundleContext(OSGi会自动绑定) public class MessageBusListener implements MessageBusListenerService { private BundleContext bundleContext; public void setBundleContext(BundleContext bundleContext) { this.bundleContext = bundleContext; } public FlowListener createFlowListener() { return new FlowListener(bundleContext); } } // FlowListener类 public class FlowListener { private final ServiceTracker<ProcessInvocationService, ProcessInvocationService> serviceTracker; public FlowListener(BundleContext bundleContext) { // 用ServiceTracker监听服务的注册/注销,避免直接getService导致的生命周期问题 serviceTracker = new ServiceTracker<>(bundleContext, ProcessInvocationService.class, null); serviceTracker.open(); } public void handleMessage(Message msg) { ProcessInvocationService service = serviceTracker.getService(); if (service != null) { service.invokeFlow(msg.getFlowId(), msg.getPayload()); } } // 记得在FlowListener销毁时关闭Tracker,避免内存泄漏 public void dispose() { serviceTracker.close(); } }
这里一定要用ServiceTracker而不是直接调用bundleContext.getService(),后者容易因为服务注销出现空指针或者内存泄漏问题,ServiceTracker会帮你自动管理服务的生命周期。
方案3:用Declarative Services(DS)工厂组件管理非服务类
如果FlowListener本身依赖很多OSGi服务,且创建逻辑复杂,可以把它做成DS的工厂组件——让OSGi帮你注入依赖,但不把它注册为公开服务:
// FlowListener标记为DS工厂组件,不暴露为服务 @Component(factory = "flowListenerFactory", service = {}) public class FlowListener { @Reference private ProcessInvocationService processInvocationService; // 可以注入更多OSGi服务... // DS调用的工厂方法,用于创建实例 @Activate public static FlowListener create(@ComponentConfigProperty(name = "flow.type", type = String.class) String flowType) { FlowListener listener = new FlowListener(); // 可以根据配置做初始化 return listener; } public void handleMessage(Message msg) { processInvocationService.invokeFlow(msg.getFlowId(), msg.getPayload()); } }
然后在MessageBusListener中通过ComponentFactory获取FlowListener实例:
public class MessageBusListener implements MessageBusListenerService { // 引用FlowListener的工厂组件 @Reference(target = "(component.factory=flowListenerFactory)") private ComponentFactory flowListenerFactory; public FlowListener createFlowListener() { // 传递配置参数(可选) Map<String, Object> props = new HashMap<>(); props.put("flow.type", "message-driven"); return (FlowListener) flowListenerFactory.newInstance(props); } }
这种方式适合FlowListener依赖复杂、需要OSGi生命周期管理的场景,同时不会把它暴露到服务注册表中。
总结一下,优先选方案1,简单低耦合;如果需要动态性或者依赖传递不便,再考虑方案2;如果FlowListener依赖多、创建逻辑复杂,方案3会更省心。
内容的提问来源于stack exchange,提问作者Udit Panchal

