如何在自定义OSGi Liberty特性中注入/查找已定义的JNDI数据源?
在Liberty中让自定义OSGi特性查找已配置的JNDI数据源
完全可行,你之前的尝试失败大概率是因为查找时机、过滤条件或环境配置的问题。以下是几种可靠的实现方式:
方式一:通过OSGi服务查找(推荐)
Liberty会将配置的<dataSource>自动注册为OSGi服务,类型为javax.sql.DataSource,并携带osgi.jndi.service.name属性(值为你配置的jndiName)。你可以通过BundleContext结合过滤条件精准定位:
// 获取你的bundle上下文 BundleContext bundleContext = ...; // 从自定义特性配置中读取目标JNDI名称 String targetJndiName = "jdbc/myDataSource"; // 创建过滤条件,匹配数据源服务的JNDI属性 Filter filter = bundleContext.createFilter("(osgi.jndi.service.name=" + targetJndiName + ")"); // 查找符合条件的数据源服务 Collection<ServiceReference<DataSource>> refs = bundleContext.getServiceReferences(DataSource.class, filter.toString()); if (!refs.isEmpty()) { DataSource dataSource = bundleContext.getService(refs.iterator().next()); // 这里可以将数据源注入到你的myJdbcRegistry组件中 }
注意:不要在bundle启动时直接同步查找,建议用ServiceTracker监听服务注册事件,确保数据源初始化完成后再获取:
ServiceTracker<DataSource, DataSource> tracker = new ServiceTracker<>(bundleContext, filter, null) { @Override public DataSource addingService(ServiceReference<DataSource> ref) { DataSource ds = super.addingService(ref); // 初始化你的myJdbcRegistry initMyJdbcRegistry(ds); return ds; } }; tracker.open();
方式二:直接进行JNDI查找
在Liberty的OSGi环境中,只要配置正确,直接通过JNDI上下文就能获取数据源:
InitialContext ctx = new InitialContext(); // 直接使用配置的jndiName查找 DataSource dataSource = (DataSource) ctx.lookup("jdbc/myDataSource");
需要满足的前提:
- 你的bundle的
MANIFEST.MF中必须导入javax.sql包:Import-Package: javax.sql;version=* - 确保在数据源完全初始化后再执行查找(同样建议用监听机制而非启动时同步执行)
方式三:利用Liberty特性扩展机制
如果是自定义Liberty特性(Feature),可以结合Config Admin读取配置,并跟踪数据源服务:
public class MyJdbcRegistryFeature implements FeatureActivator { private ServiceTracker<DataSource, DataSource> dataSourceTracker; @Override public void activate(BundleContext context) { // 读取<myJdbcRegistry>配置中的dataSourceJndiName ConfigAdmin configAdmin = context.getService(context.getServiceReference(ConfigAdmin.class)); Dictionary<String, Object> configProps = configAdmin.getConfiguration("com.yourcompany.myJdbcRegistry").getProperties(); String jndiName = (String) configProps.get("dataSourceJndiName"); // 跟踪对应JNDI名称的数据源服务 Filter filter = context.createFilter("(osgi.jndi.service.name=" + jndiName + ")"); dataSourceTracker = new ServiceTracker<>(context, filter, null) { @Override public DataSource addingService(ServiceReference<DataSource> ref) { DataSource ds = super.addingService(ref); // 初始化自定义注册表组件 MyJdbcRegistry registry = new MyJdbcRegistry(); registry.setDataSource(ds); return ds; } }; dataSourceTracker.open(); } @Override public void deactivate(BundleContext context) { if (dataSourceTracker != null) { dataSourceTracker.close(); } } }
你之前失败的常见原因
- 查找时机过早:在数据源服务还未完成注册时就执行查找
- 过滤条件错误:误用了
jndiName作为OSGi服务属性,正确属性是osgi.jndi.service.name - 类依赖缺失:bundle未导入
javax.sql或JNDI相关包 - JNDI环境配置错误:默认InitialContext无法访问Liberty全局JNDI上下文(方式二已规避此问题)
内容的提问来源于stack exchange,提问作者Nikola
相关产品推荐
相关产品推荐

