Org.springframework.jndi.JndiLookupFailureException 对于 Websphere 上的 Cron 调度程序

Org.springframework.jndi.JndiLookupFailureException For Cron Scheduler On Websphere

我正在做一个项目,我必须以固定的时间间隔调用一个函数,该函数使用 jndi 与数据库交互以提供一些值。该项目在 tomcat 上运行良好,但在 Websphere 上部署时出现 JndiLookupFailureException。但是,如果我们使用使用 url 的手动命中调用相同的函数,该函数将在 websphere 上成功执行,而不会给出任何 jndi 异常。我认为问题出在 cron 调度程序 但没有找到确切的根本原因。

详情如下:

1) web.xml

<resource-ref>
    <res-ref-name>jdbc/dummyJndi</res-ref-name>
    <res-type>oracle.jdbc.pool.OracleDataSource</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
  </resource-ref>

2) database.xml

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="java:comp/env/jdbc/dummyJndi" />
        <property name="lookupOnStartup" value="false" />
        <property name="cache" value="true" />
        <property name="proxyInterface" value="javax.sql.DataSource" /> 
    </bean> 

3) scheduler.xml

<task:scheduled-tasks>
        <task:scheduled ref="sampleService" method="getData"
            cron="0 0/20 * * * ?" />
    </task:scheduled-tasks>

<bean id="sampleService"
class="com.service.SampleService">  
    </bean>

4) Websphere 异常

org.springframework.jndi.JndiLookupFailureException: JndiObjectTargetSource failed to obtain new target object; nested exception is javax.naming.ConfigurationException: A JNDI operation on a "java:" name cannot be completed because the server runtime is not able to associate the operation's thread with any J2EE application component.  This condition can occur when the JNDI client using the "java:" name is not executed on the thread of a server application request.  Make sure that a J2EE application does not execute JNDI operations on "java:" names within static code blocks or in threads created by that J2EE application.  Such code does not necessarily run on the thread of a server application request and therefore is not supported by JNDI operations on "java:" names. [Root exception is javax.naming.NameNotFoundException: Name comp/env/jdbc not found in context "java:".]
    at org.springframework.jndi.JndiObjectTargetSource.getTarget(JndiObjectTargetSource.java:139)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:182)
    at com.sun.proxy.$Proxy940.getConnection(Unknown Source)
    at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111)
    at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:381)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:455)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:463)
    at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:471)
    at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:476)
    at org.springframework.jdbc.core.JdbcTemplate.queryForInt(JdbcTemplate.java:485)

不确定这是否是原因,但资源引用类型应该是规范接口,

<res-type>javax.sql.DataSource</res-type>

而不是 JDBC 供应商实施 class,

<res-type>oracle.jdbc.pool.OracleDataSource</res-type>

我给点建议。您可以一一尝试。希望对你有帮助。

建议#1:

在你的database.xml中,使用

<property name="jndiName" value="jdbc/dummyJndi" />

而不是

<property name="jndiName" value="java:comp/env/jdbc/dummyJndi" />

有时,它可以解决问题。

资源Link:

https://www.ibm.com/developerworks/community/forums/html/topic?id=77777777-0000-0000-0000-000013872292


建议#2

问题:

"javax.naming.NamingException - Name comp/env/jdbc not found in context "java:"

根本原因分析:

导致此异常的最可能原因是应用程序进行了间接 JNDI 查找,但查找的资源不存在资源引用。为了提供一些背景信息,WebSphere Application Server 中有两种不同类型的 JNDI 查找: 当应用程序查找绑定到名称空间的资源的物理 JNDI 名称时,会发生直接或全局 JNDI 查找。例如,如果数据源的 JNDI 名称是 "jdbc/myDS",查找将如下所示:

DataSource ds = (DataSource)ctx.lookup("jdbc/myDS");

当应用程序查找映射到物理 JNDI 名称的资源引用时,会发生间接或本地 JNDI 查找。资源引用在应用程序部署描述符中定义,web.xml 用于 Web 模块,ejb-jar.xml 用于 EJB 模块,application-client.xml 用于应用程序客户端模块。例如,如果资源引用名称是 "jdbc/myDSresref",查找将如下所示:

DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/myDSresref");

间接 JNDI 查找被认为是 J2EE 最佳实践。间接 JNDI 查找的优点是它使您的应用程序更易于维护。如果资源的实际 JNDI 名称发生变化,则无需对您的应用程序进行任何更改。这是因为资源的 JNDI 名称存储在资源引用中,而不是应用程序代码中。

如果应用程序模块中不存在资源引用,JNDI 查找将失败并出现上述javax.naming.NamingException。同样重要的是要注意,间接 JNDI 查找只能从 J2EE 容器(Web 模块、EJB 模块或应用程序客户端模块)内的应用程序完成。

解决问题:

要解决此问题,您需要在 Web、EJB 或应用程序客户端模块的部署描述符中创建资源引用,并将其映射到资源的物理 JNDI 名称。这可以使用 Application Server Toolkit (AST)、WebSphere Studio Application Developer (WSAD) 或 Rational Application Developer (RAD) 来完成。

创建或更改资源引用http://pic.dhe.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/com.ibm.websphere.nd.doc/info/ae/ae/tatk_crtresref.html

当间接 JNDI 查找完成时,资源引用的名称是 JNDI 名称中“java:comp/env”之后的部分。配置资源引用时,资源的物理JNDI名称设置为JNDI绑定。

资源Link:

http://www-01.ibm.com/support/docview.wss?uid=swg21106933

建议#3:

Spring boot JNDI datasource lookup failure - Name comp/env/jdbc not found in context "java:"