如何在Apache Tomcat 7.x中访问Context容器之外的全局JNDI资源?

时间:2014-11-14 12:31:50

标签: tomcat7 jndi tomcat-valve

我正在为Apache Tomcat 7开发自定义Valve,该阀门在Apache Tomcat Host container配置文件中定义为server.xml级别。

<Engine defaultHost="localhost" name="Catalina">

    <Realm className="org.apache.catalina.realm.DataSourceRealm" dataSourceName="jdbc/qgw" 
    roleNameCol="role_name" userCredCol="user_pass" userNameCol="user_name" userRoleTable="user_roles" userTable="users"/>

    <Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">
        <Valve className="org.mycompany.valves.CustomValve"/>
        <Valve className="org.apache.catalina.authenticator.SingleSignOn"/>
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" 
        pattern="%h %l %u %t &quot;%r&quot; %s %b" prefix="localhost_access_log." suffix=".txt"/>
    </Host>

</Engine>

阀门需要与数据库建立连接以进行一些查询。

我正在尝试在GlobalNamingResources中将JNDI资源定义为全局资源。

<GlobalNamingResources>
    <Resource auth="Container" driverClassName="com.mysql.jdbc.Driver" 
    logAbandoned="true" maxActive="25" maxIdle="10" name="jdbc/qgw" 
    password="pass" removeAbandoned="true" removeAbandonedTimeout="300" 
    testOnBorrow="true" type="javax.sql.DataSource" 
    url="jdbc:mysql://localhost/qgw?autoReconnect=true" 
    username="username" validationQuery="SELECT 1"/>
</GlobalNamingResources>

问题是,资源只能在Context容器级别访问,因为在context.xml配置文件中定义了ResourceLink

<ResourceLink global="jdbc/qgw" name="jdbc/qgw" type="javax.sql.DataSource"/> 

显然,当阀门尝试通过JNDI获取数据源时

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

获取NameNotFoundException

javax.naming.NameNotFoundException: Name comp/env/jdbc/qgw is not bound in this Context

那么,有没有办法在Host Container级别使用资源连接到定义的数据库?

2 个答案:

答案 0 :(得分:1)

经过很长一段时间,这是我找到DataSource,从container获取卡塔利娜StandardService的唯一途径,我不知道这是否是最好的实现这一目标的方法,但它确实有效。

private static final String RESOURCE = "jdbc/qgw";

private DataSource ds;

@Override
protected synchronized void startInternal() throws LifecycleException {
    super.startInternal();

    StandardService service = (StandardService)((StandardEngine)((StandardHost) container).getParent()).getService();
    try {
        // Accesible via GlobalNamingResources too
        //service.getServer().getGlobalNamingResources().findResource(RESOURCE);
        ds = (DataSource)service.getServer().getGlobalNamingContext().lookup(RESOURCE);
        if (ds==null) {
            throw new LifecycleException("Can't get the datasource to connect to database from the valve.");
        }
    } catch (Exception e) {
        container.getLogger().error(e);
        throw new LifecycleException(e.getMessage());
    }
}

答案 1 :(得分:1)

您也可以尝试在Java根目录下查找:

InitialContext initCtx = new InitialContext();
DataSource ds = (DataSource)initCtx.lookup("java:jdbc/qgw");