JNDI(Java Naming and Directory Interface–Java命名和目录接口)

发布时间 2023-04-02 20:10:33作者: 围观的小妖g

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源码深度解析》