JNDI(Java Naming and Directory Interface,Java命名和目录接口)为应用程序提供了一种通过网络访问远程服务的方式。本节我们学习如何通过JNDI API注册和访问JDBC数据源对象。读者如果需要了解更多JNDI相关细节,则可参考JNDI规范文档。
JNDI API的命名服务可以把一个逻辑名称和一个具体的对象绑定。使用JNDI API,应用程序可以通过与DataSource对象绑定的逻辑名称来获取DataSource对象,这种方式在很大程度上提高了应用的可移植性,因为当DataSource对象的属性(例如端口号、服务器地址等)被修改时,不会影响JDBC客户端代码。实际上,当修改DataSource的配置,使它连接到其他数据库时,应用程序是没有任何感知的。
接下来我们就以一个实际的案例介绍如何使用JNDI API提供一个命名服务,然后使用JNDI API查找该命名服务,代码如下:
@Before
public void before() throws IOException {
DataSourceFactory dsf = new UnpooledDataSourceFactory();
Properties properties = new Properties();
InputStream configStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("database.properties");
properties.load(configStream);
dsf.setProperties(properties);
DataSource dataSource = dsf.getDataSource();
try {
Properties jndiProps = new Properties();
jndiProps.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory");
jndiProps.put(Context.URL_PKG_PREFIXES, "org.apache.naming");
Context ctx = new InitialContext(jndiProps);
ctx.bind("java:TestDC", dataSource);
} catch (NamingException e) {
e.printStackTrace();
}
}
@Test
public void jdniTest() {
try {
Properties jndiProps = new Properties();
jndiProps.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory");
jndiProps.put(Context.URL_PKG_PREFIXES, "org.apache.naming");
Context ctx = new InitialContext(jndiProps);
DataSource dataSource = (DataSource) ctx.lookup("java:TestDC");
Connection conn = dataSource.getConnection();
Assert.assertNotNull(conn);
} catch (Exception e) {
e.printStackTrace();
}
}
如上面的代码所示,在MyBatis源码中提供了javax.sql.DataSource接口的实现,分别为UnpooledDataSource和PooledDataSource类。UnpooledDataSource未实现连接池功能,而PooledDataSource则采用装饰器模式对UnpooledDataSource功能进行了增强,增加了连接池管理功能。
上面的代码中,我们使用UnpooledDataSourceFactory创建了一个UnpooledDataSource实例,其中database.properties文件为数据源相关配置(读者可参考mybatis-chapter02项目中的database.properties文件内容),然后创建一个javax.naming.InitialContext实例,调用该实例的bind()方法创建命名服务,命名服务创建完成后就可以通过javax.naming.InitialContext实例的lookup()方法来查找服务了。
需要注意的是,JDK中只提供了JNDI规范,具体的实现由不同的厂商来完成。这里我们使用的是Apache Tomcat中提供的JNDI实现,因此需要在项目中添加相关依赖,例如:
<dependency>
<groupId>tomcat</groupId>
<artifactId>naming-java</artifactId>
<version>5.0.28</version>
</dependency>
<dependency>
<groupId>tomcat</groupId>
<artifactId>naming-common</artifactId>
<version>5.0.28</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
在实际的Java EE项目中,JNDI命名服务的创建通常由应用服务器来完成。在应用程序中,我们只需要查找命名服务并使用即可。例如,在Apache Tomcat服务器中,我们可以通过如下代码配置JNDI数据源:
JNDI规范文档:https://docs.oracle.com/cd/E17802_01/products/products/jndi/javadoc/
注意:摘要于《mybatis3源码深度解析》