Tomcat-9.JNDI资源

2019-05-16  本文已影响0人  悠扬前奏

JNDI(Java Naming and Directory Interface,Java命名和目录接口)是一个应用程序设计的API,为开发人员提供了查找和访问各种命名和目录服务的通用、统一的接口。

1.介绍

Tomcat为每个在其上运行的web应用提供了一个JNDI的** InitialContext**实现实例,它与Java EE应用服务器提供的对应类完全兼容。
Java EE标准在/WEB-INF/web.xml文件中提供了一系列标准元素,用来引用或者定义资源。

2.web.xml配置

可在web应用的部署描述文件(WEB-INF/web.xml)中使用下列元素来定义资源:

通过以上配置,Tomcat就会选择适宜的资源工厂来创建资源,不需要别的信息。Tomcat将会使用/WEB-INF/web.xml中的信息来创建资源。

此外,Tomcat还提供了一些用于JNDI的特殊选项,需要指定在web应用的<Context>元素内,或者位于$CATALINA_BASE/conf/server.xml的<GlobalNamingResources>元素中。

3.context.xml配置

TOmcat特定资源配置位于<Context>元素内,它可以指定在$CATALINA-BASE/conf/server.xml中,或者,最好放在每个web应用的上下文xml文件(META-INF/context.xml)中
要完成Tomcat的特定资源的配置,需要使用<Context>元素中的下列元素:

一个资源名称既被定义在web应用描述文件的<env-entry>元素中,又被定义在web应用的<Context>元素的<Environment>元素内,那么只有当相应的<Environment>元素被允许(将其中的override属性设置为true),部署描述文件中的值才会优先对待。

4.全局配置

Tomcat为整个服务器维护着一个全局资源的独立命名空间,这些全局资源配置在$CATALINA_BASE/conf/server.xml的<GlobalNamingResources>元素内。可以使用<ResourcesLink>将这些资源暴露给web应用,以便在每一个应用上下文中将其包含进来。
如果已经使用<ResourceLink>定义了资源,那就不必在/WEB-INF/web.xml文件中定义了。但是建议在/WEB-INF/web.xml文件中保留相关项,以便记录应用资源请求。

5. 使用资源

在web应用最初部署时候,就配置InitialContext,使其可以被web应用的各组件所访问(只读访问)。
JNDI命名空间的java:comp/env部分中包含着所有的配置项与资源。所以访问资源例子(JDBC数据源)如下:

// Obtain our environment naming context
// 获取环境命名上下文
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");

// Look up our data source
// 查找数据源
DataSource ds = (DataSource)
  envCtx.lookup("jdbc/EmployeeDB");

// Allocate and use a connection from the pool
// 分配并使用池中的连接
Connection conn = ds.getConnection();
... use this connection to access the database ...
conn.close();

6 标准资源工厂

Tomcat包含一系列资源工厂,为Web应用提供各种服务,通过<Context>元素可以在不修改web应用或者部署描述文件的情况下进行配置。
创建,安装,配置和使用自己的自定义资源工厂类,参看添加自定义资源工厂
“JDBC DataSource”和“User Transaction”工厂可适用于其他实现了Java EE的其他平台,其他所有的标准资源工厂,以及自行编写的,都是Tomcat专属。

6.1 一般JavaBean资源

6.1.0 简介

该资源工厂能够创建任何符合标准JavaBean命名规范的Java类的对象。如果工厂的singleton属性被设置为false,那么每当对该项进行lookup时,资源工厂会创建出合适的bean类的新实例。
步骤如下:

6.1.1 创建JavaBean类

创建一个JavaBean类,在每次查找资源工厂时,就创建他的实例。

package com.mycompany;

public class MyBean {

  private String foo = "Default Foo";

  public String getFoo() {
    return (this.foo);
  }

  public void setFoo(String foo) {
    this.foo = foo;
  }

  private int bar = 0;

  public int getBar() {
    return (this.bar);
  }

  public void setBar(int bar) {
    this.bar = bar;
  }
}

6.1.2 声明资源需求

修改Web应用部署描述文件(WEB-INF/web.xml)声明JNDI名称,并据此请求该Bean类的新实例。

<resource-env-ref>
  <description>
    Object factory for MyBean instances.
  </description>
  <resource-env-ref-name>
    bean/MyBeanFactory
  </resource-env-ref-name>
  <resource-env-ref-type>
    com.mycompany.MyBean
  </resource-env-ref-type>
</resource-env-ref>

6.1.3 使用资源

资源引用的典型用例如下:

Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
MyBean bean = (MyBean) envCtx.lookup("bean/MyBeanFactory");

writer.println("foo = " + bean.getFoo() + ", bar = " +
               bean.getBar());

6.1.4 配置Tomcat资源工厂

为了配置Tomcat资源工厂,为Web应用的<Context>元素添加下列元素:

<Context ...>
  ...
  <Resource name="bean/MyBeanFactory" auth="Container"
            type="com.mycompany.MyBean"
            factory="org.apache.naming.factory.BeanFactory"
            bar="23"/>
  ...
</Context>

6.2 UserDataBase资源

6.2.0 简介

UserDataBase资源通常被配置成通过UserDatabaseRealm所使用的全局资源。Tomcat包含一个UserDatabaseFactory,能够叉棍件基于XML文件(通常是tomcat-users.xml)的UserDatabase资源。
简历全局UserDatabase资源的步骤为:

6.2.1 创建/编辑XML文件

XML文件通常位于$CATALINA_BASE/conf/tomcat-users.xml,但是也可以放在文件系统的任何位置。
典型XML应如下所示:

<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
  <role rolename="tomcat"/>
  <role rolename="role1"/>
  <user username="tomcat" password="tomcat" roles="tomcat"/>
  <user username="both" password="tomcat" roles="tomcat,role1"/>
  <user username="role1" password="tomcat" roles="role1"/>
</tomcat-users>

6.2.2 声明资源

修改$CATALINA_BASE/conf/server.xml来创建基于此文件的UserDatabase资源:

<Resource name="UserDatabase"
          auth="Container"
          type="org.apache.catalina.UserDatabase"
          description="User database that can be updated and saved"
          factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
          pathname="conf/tomcat-users.xml"
          readonly="false" />

属性pathname可以采用绝对路径或者相对路径,相对路径是相对于$CATALINA_BASE
属性readonly可选,默认为true。

6.2.4 配置Realm

配置UserDatabase Realm以便使用该资源。参考Realm配置文档

6.3 JavaMail会话

6.3.0 简介

Tomcat 多包涵的标准资源工厂可以创建javax.mail.Session会话实例,并且已经配置好连接SMTP服务器上,从而使应用与电子邮件配置环境隔离。无论何时,只需要请求并接受预配置的会话即可。

6.3.1 声明资源需求

修改web应用的部署描述文件(/WEB-INF/web.xml)声明JNDI名称以便借此查找预配置会话。按照惯例,所有这样的名字都应该解析道mai子上下文。
典型的web.xml配置为:

<resource-ref>
  <description>
    Resource reference to a factory for javax.mail.Session
    instances that may be used for sending electronic mail
    messages, preconfigured to connect to the appropriate
    SMTP server.
  </description>
  <res-ref-name>
    mail/Session
  </res-ref-name>
  <res-type>
    javax.mail.Session
  </res-type>
  <res-auth>
    Container
  </res-auth>
</resource-ref>

注意:要遵循web应用部署文件中DTD所需要的元素顺序。参考Servlet规范

6.3.2 使用资源

典型的资源引用用例:

Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
Session session = (Session) envCtx.lookup("mail/Session");

Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(request.getParameter("from")));
InternetAddress to[] = new InternetAddress[1];
to[0] = new InternetAddress(request.getParameter("to"));
message.setRecipients(Message.RecipientType.TO, to);
message.setSubject(request.getParameter("subject"));
message.setContent(request.getParameter("content"), "text/plain");
Transport.send(message);

该应用引用的资源引用名与Web应用部署符中声明的完全相同。

6.3.3 配置Tomcat资源工厂

为了配置资源工厂,在<Context>元素中添加以下元素:

<Context ...>
  ...
  <Resource name="mail/Session" auth="Container"
            type="javax.mail.Session"
            mail.smtp.host="localhost"/>
  ...
</Context>

注意,资源名(这里是mail/Session)必须与web应用部署描述文件中的值相匹配。对于mail.smtp.host参数,可以用为你提供SMTP服务的服务器来自定义。
额外的资源属性与值将会被转换成相关的属性和值被传入javax.mail.Session.getInstance(java.util.Properties),作为参数集java.util.Properties中的一部分。
如果资源配置中包含password属性,以及mail.smtp.user或者mail.user属性,那么Tomcat资源工厂将配置添加javax.mail.Authenticator到邮件Session中。

6.3.4 安装Java Mail库

下载JavaMail API
解压缩后,将mail.jar放到CATALINA_HOME/lib中。 注意:不能将这个文件同时放在CATALINA_HOME/lib和web应用的/lib文件夹中。

6.3.5 重启Tomcat

为了使用这个额外的jar文件,需要重启Tomcat实例。

6.3.6 范例应用

Tomcat的/examples 应用中有一个使用该资源工厂的范例。可以通过“JSP范例”的链接来访问它。实际发送邮件的servlet源代位于/WEB-INFO/classes/SendMailServlet.java中。

默认配置在localhost的端口25上的SMTP服务器。如果和实际情况不符合,需要编辑web应用的<Context>元素,将mail.smtp.host参数的值修改为你的网络上的SMTP服务器的主机名。

6.4 JDBC数据源

6.4.1 安装JDBC驱动

将驱动的JAR文件安装到CATALINA_HOME/lib目录中,资源工厂就都能使用这个JDBC驱动了。

6.4.2 声明资源需求

修改web应用的部署描述文件(/WEB-INF/web.xml),声明JNDI名称以便借此查找预配置的数据源。
按照惯例这样的名称应该在jdbc子上下文中声明(“子”是相对于标准的java:comp/env环境命名上下文而言的。)。
典型的web.xml文件如下:

<resource-ref>
  <description>
    Resource reference to a factory for java.sql.Connection
    instances that may be used for talking to a particular
    database that is configured in the <Context>
    configuration for the web application.
  </description>
  <res-ref-name>
    jdbc/EmployeeDB
  </res-ref-name>
  <res-type>
    javax.sql.DataSource
  </res-type>
  <res-auth>
    Container
  </res-auth>
</resource-ref>

注意:一定要遵从web应用部署描述文件中DTD所需要的元素顺序。

6.3.3 使用资源

资源的典型引用用例:

Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
DataSource ds = (DataSource)
  envCtx.lookup("jdbc/EmployeeDB");

Connection conn = ds.getConnection();
... use this connection to access the database ...
conn.close();

注意:这里的资源引用名与web应用部署符中的完全相同。

6.3.4 配置Tomcat资源工厂

为了配置Tomcat资源工厂,在<Context>元素中配置以下元素:

<Context ...>
  ...
  <Resource name="jdbc/EmployeeDB"
            auth="Container"
            type="javax.sql.DataSource"
            username="dbusername"
            password="dbpassword"
            driverClassName="org.hsql.jdbcDriver"
            url="jdbc:HypersonicSQL:database"
            maxTotal="8"
            maxIdle="4"/>
  ...
</Context>

Tomcat标准资源工厂(org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory)的配置属性如下:

额外用来验证连接的属性:

可选的evictor thread会清楚空闲时间较长的连接,从而缩小连接池。evictor thread不受minIndle属性值的空闲。
如果只想通过配置的minIdle属性来缩小连接池,那么不需要使用evictor thread
默认evictor是禁用的,可以通过下列属性来配置它:

可选的配置废弃连接的移除。如果应用很久不把某个连接返回连接池,那么该连接被称为废弃连接,连接池会自动关闭这样的连接,将其从连接池中移除。
默认禁止废弃连接,通过下列属性来配置:

连接池行为的属性微调:

6.4 自定义资源工厂

如果标准工厂无法满足需求,可以自行编写资源工厂,然后集成到Tomcat中。

6.4.1 编写资源工厂类

需要编写一个类来实现JNDI服务提供者javax.naming.spi.ObjectFactory接口。web应用绑定到该工厂(假设工厂配置中singleton="false")的上下文项上调用lookup()时,就会调用getObjectInstance()方法,该方法参数如下:

创建一个能够生成MyBean实例的资源工厂:

package com.mycompany;

import java.util.Enumeration;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.spi.ObjectFactory;

public class MyBeanFactory implements ObjectFactory {

  public Object getObjectInstance(Object obj,
      Name name2, Context nameCtx, Hashtable environment)
      throws NamingException {

      // Acquire an instance of our specified bean class
      MyBean bean = new MyBean();

      // Customize the bean properties from our attributes
      Reference ref = (Reference) obj;
      Enumeration addrs = ref.getAll();
      while (addrs.hasMoreElements()) {
          RefAddr addr = (RefAddr) addrs.nextElement();
          String name = addr.getType();
          String value = (String) addr.getContent();
          if (name.equals("foo")) {
              bean.setFoo(value);
          } else if (name.equals("bar")) {
              try {
                  bean.setBar(Integer.parseInt(value));
              } catch (NumberFormatException e) {
                  throw new NamingException("Invalid 'bar' value " + value);
              }
          }
      }

      // Return the customized instance
      return (bean);

  }

}

首先参照CATALINA_HOME/lib目录中包含所有的JAR文件的类路径来编译该类,完成之后,将这个工厂类以及相应的Bean类解压到CATALINA_HOME/lib,或者$CATALINA_HOME/lib中的一个JAR文件中,这样,所需的类文件就能被Catalina内部资源和web应用看到了。

6.4.2 声明资源需求

修改web应用的部署描述文件(WEB-INF/web.xml)声明JNDI名称以便借此请求bean的新实例,最简单的方法是使用<resource-env-ref>元素:

<resource-env-ref>
  <description>
    Object factory for MyBean instances.
  </description>
  <resource-env-ref-name>
    bean/MyBeanFactory
  </resource-env-ref-name>
  <resource-env-ref-type>
    com.mycompany.MyBean
  </resource-env-ref-type>
</resource-env-ref>

6.4.3 使用资源

资源引用的典型用例:

Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
MyBean bean = (MyBean) envCtx.lookup("bean/MyBeanFactory");

writer.println("foo = " + bean.getFoo() + ", bar = " +
               bean.getBar());

6.4.4 配置Tomcat资源工厂

为了配置Tomcat资源工厂,在<Context>中添加以下元素:

<Context ...>
  ...
  <Resource name="bean/MyBeanFactory" auth="Container"
            type="com.mycompany.MyBean"
            factory="com.mycompany.MyBeanFactory"
            singleton="false"
            bar="23"/>
  ...
</Context>
上一篇下一篇

猜你喜欢

热点阅读