无法在GWT + Hibernate + MySQL项目中配置MySQL数据源

4
我正在试图将一个 JSP/Hibernate 项目迁移到 GWT/Hibernate 上。简而言之,问题似乎在于来自 jetty-env.xml 的 MysqlConnectionPoolDataSource 类明显没有被实例化,导致 web.xml 中的资源引用失败。
我们的 Hibernate 设置在非 GWT 项目中运作良好。我正在使用 Eclipse Indigo、Google Suite Plugin 2.5 和 Google GWT Designer 2.4.2。
以下是我所采取的步骤和我认为相关的文件摘录。(事先道歉 - 这有点冗长,但我希望确保我的问题是完整和清晰的。)
我的 war/WEB-INF/classes/hibernate.cfg.xml 包括:
<property name="hibernate.connection.datasource">
    java:comp/env/jdbc/nndb
</property>

web.xml包含:

<resource-ref>
    <description>NN Database Connection Pooling</description>
    <res-ref-name>jdbc/nndb</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

我还按照这里所述创建了CustomJettyLauncher,并添加了Eclipse运行配置以使用它(运行配置参数- server com....CustomJettyLauncher)。 这导致出现以下情况:
jetty-6.1.x [WARN] NN数据库连接池jdbc / nndbjavax.sql.DataSourceContainerShareable的配置问题 java.lang.IllegalStateException:没有要绑定的名称javax.sql.DataSource / default
我推测此时需要在jetty-env.xml中定义资源条目。
<?xml version="1.0"?> <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure class="org.mortbay.jetty.webapp.WebAppContext">
    <New id="nndb" class="org.mortbay.jetty.plus.naming.Resource">
        <Arg>jdbc/nndb</Arg>
        <Arg> 
            <New class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource">
               <Set name="Url">jdbc:mysql://dbserver/dbname</Set>
               <Set name="User">dbuser</Set>
               <Set name="Password">dbpasswd</Set>
            </New>
        </Arg>
   </New>
</Configure>

但上述错误(Nothing to bind for name javax.sql.DataSource/default)仍然存在。有趣的是,如果我故意在jetty-env.xml中搞砸数据源类名(例如NOSUCH.com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource),它不会抱怨,所以它甚至可能没有尝试实例化那个类。(类似于WebAppContext和Resource DO的“tracer”错误确实会产生抱怨,因此只有ConnectionPoolDataSource不尝试实例化。)
呼!
有人看出问题了吗?任何建议都将不胜感激。
提前致谢!

你是在客户端还是服务器端尝试实例化PoolDataSource? - Johanna
假设您完全遵循了启动器教程并将jetty-namingjetty-plus的JAR文件放置在 WEB-INF/lib 目录下,我想知道你的jetty-env.xml是否被“构建”了 - 请验证它是否被复制到您的bin目录中,以便项目可以成功启动? - Pavel Veller
WEB-INF/lib目录下有jetty-naming和jetty-plus的jar包,而WEB-INF目录下有jetty-env.xml文件。我知道jetty正在尝试使用jetty-env.xml文件,因为如果我故意弄乱WebAppContext和Resource类名,它会抱怨,但如果我对MysqlConnectionPoolDataSource这个类名进行同样的操作,比如NOSUCH.com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource,它却不会抱怨。 - Bill Compton
@BillCompton,当您将日志级别设置为“DEBUG”时,是否看到“Created java:comp/env for webapp”?然后,您是否看到“Binding env entries from the context scope”?这将来自负责“jetty-env.xml”的org.mortbay.jetty.plus.webapp.EnvConfiguration。我希望能够获得您的项目代码以进行测试。也许您可以在Dropbox上上传一个简化版本? - Pavel Veller
@PavelVeller,两个更新:1)在处理提取的项目时,我注意到我有Jetty 6.1.26,但GWT 2.4.0似乎是使用Jetty 6.1.11构建的。将WEB-INF / lib中的jar切换为Jetty 6.1.11后,Jetty现在会抱怨找不到NOSUCH.com ... MysqlConnectionPoolDataSource的错误路径,因此它现在至少尝试实例化该类。但是,使用正确的路径仍然会失败,出现名称javax.sql.DataSource / default无法绑定的情况。2)我尝试遵循JETTY /调试说明(在WEB-INF / lib和路径中添加slf4j),添加了-DDEBUG vm arg,但没有日志记录。求助? - Bill Compton
显示剩余5条评论
3个回答

2
在玩了你的项目代码后,我不得不完全更改我的答案。这是一个新的答案:

你使用的Jetty Launcher代码来自较早版本的GWT(我认为)。一旦我用我自己的版本替换了你的CustomJettyLauncher(按照相同的建议进行修改,但是基于GWT 2.4代码库),一切就都成立了。适当初始化初始上下文、java:comp/env等。

实际上,如果你在jetty-env.xml中将名称中添加java:comp/env,你也可以使你的版本与6.1.11一起工作,但我认为这条路没有意义。我无法使其与6.1.26一起工作,但这并不重要,因为使用适当的Jetty Launcher代码库使其可以与任何版本一起工作

这是有效的启动器代码(包和类名与你的相同,因此它是一个“插入式”替换):https://gist.github.com/2854726


给以后可能会遇到这篇文章的人留下线索。你可以通过使用SPAM日志级别启动GWT,在GWT托管(dev)模式下显示Jetty的DEBUG日志。


1

在我们在评论中的交谈之后,我决定继续构建一个简单的“hello world”本地应用程序,以查看是否可以重现该问题。我必须经历一些麻烦,但不是你描述的那种。 我现在想知道您的类路径上是否有任何冲突版本的jetty库。例如,请参阅这里的问题。以防万一,我还必须处理与GWT托管模式、类加载和Hibernate相关的其他问题(这里更多更多)。现在一切都清楚了,我的简单示例正在运行

回到您的情况。通过查看已修补的Jetty启动器,我弄清了GWT对Jetty日志子系统的影响。请看内部类JettyTreeLogger。它将所有INFO及以下级别的日志发送到SPAM。除非您使用SPAM日志级别运行GWT应用程序,否则您将无法看到需要诊断您的情况所需的“宝贵”Jetty输出。因此,请在运行配置(GWT选项卡)中打开SPAM日志级别,或者进一步修补已修补的启动器以不吞噬Jetty日志消息。
按照设置自己的Jetty Launcher并使用SPAM日志级别运行GWT的步骤后,我能够在控制台中看到以下内容:
...
Created java:comp/env for webapp /
Finding global env entries
...
parse: file:/.../JettyHibernateExample/war/WEB-INF/jetty-env.xml
...
loaded class com.mysql.jdbc.jdbc2.optional.MysqlDataSource from ContextLoader@null
XML new class com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
...
XML new class org.mortbay.jetty.plus.naming.Resource
...
Looking up name="jdbc"
Looking up binding for jdbc for context=env
...
Subcontext jdbc created
Adding binding with key=nndb obj=Reference Class Name: com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource

它成功地解析了配置并正确地绑定了创建的对象。在日志中进一步查看:

May 30, 2012 5:27:33 PM org.hibernate.cfg.Configuration configure
INFO: HHH000043: Configuring from resource: /hibernate.cfg.xml
...
DEBUG org.hibernate.cfg.Configuration -
hibernate.connection.datasource=java:comp/env/jdbc/nndb
...
DEBUG org.hibernate.internal.SessionImpl - Opened session at timestamp
DEBUG org.hibernate.internal.SessionImpl - Disconnecting session
DEBUG o.h.e.j.i.LogicalConnectionImpl - Releasing JDBC connection

成功实例化了一个SessionFactory,打开并随后断开了Session。我没有进一步测试它,因为我认为从这里开始一切都很好。

这是我在WEB-INF/lib中拥有的依赖项列表:

antlr-2.7.7.jar
dom4j-1.6.1.jar
gwt-servlet.jar
hibernate-commons-annotations-4.0.1.Final.jar
hibernate-core-4.1.3.Final.jar
hibernate-jpa-2.0-api-1.0.1.Final.jar
hibernate-validator-4.1.0.Final.jar
javassist-3.15.0-GA.jar
jboss-logging-3.1.0.GA.jar
jboss-transaction-api_1.1_spec-1.0.0.Final.jar
jetty-naming-6.1.11.jar
jetty-plus-6.1.11.jar
logback-classic-1.0.1.jar
logback-core-1.0.1.jar
mysql-connector-java-5.1.20-bin.jar
report
slf4j-api-1.6.4.jar
validation-api-1.0.0.GA.jar

我希望你打开日志后能够看到问题所在。如果需要进一步的帮助,请随时分享它以供我们查看。

更新 现在有了您的日志文件进行检查,我将开始提出更多建议。我注意到的第一件事是,您的web.xml似乎没有遵循元素的DTD顺序。您的resource-ref应该在servletservlet-mappingwelcome-file-list之后。不过这似乎并不重要。

当您说

@ different versions: project classpath: 6.1.26 but 6.1.11 in WEB-INF/lib

时,您能否告诉我确切的意思?我想确保类路径不是问题,并且我们在运行时没有多个Jetty JAR发生冲突。请与WEB-INF/lib中的所有内容一起分享您的.classpath项目文件。

更新2 我发现您的日志文件和我的事件顺序有所不同。我会直接切入主题。

在Jetty 6.1.11中:

public void configureWebApp() throws Exception
{
    //create a java:comp/env
    createEnvContext();

    //add java:comp/env entries for any globally defined EnvEntries
    bindGlobalEnvEntries();

    //set up java:comp/env as the Context in which to bind directly
    //the entries in jetty-env.xml
    NamingEntry.setScope(NamingEntry.SCOPE_LOCAL);

    //check to see if an explicit file has been set, if not,
    //look in WEB-INF/jetty-env.xml
    ....
}

在Jetty 6.1.26中:

public void configureWebApp() throws Exception
{
    //check to see if an explicit file has been set, if not,
    //look in WEB-INF/jetty-env.xml
    ...
}

创建上下文已移至:

public void configureDefaults() throws Exception
{        
    //create a java:comp/env
    createEnvContext();
}

它没有设置SCOPE_LOCAL。没有SCOPE_LOCAL,根上下文就不是应该是java:comp/env。在6.1.26(plusnaming)中运行,我现在可以看到“有问题的”:

Looking up binding for __ for context=null

话虽如此,它仍然可以正常工作。那个“范围”逻辑现在必须存在于其他地方,只要您拥有6.1.26(并且没有来自早期版本的任何冲突类),它应该可以正常工作。您的代码中可能会出现以下内容:
Looking up name="__/jdbc/nndb"
Looking up binding for __ for context=null
InitialContextFactory.getInitialContext()
Created initial context delegate for local namespace:org.mortbay.naming.local.localContextRoot@237c8a9c
InitialContextFactory.getInitialContext()
Created initial context delegate for local namespace:org.mortbay.naming.local.localContextRoot@457019f7
Looking up name="Server@1c9e8392/__/javax.sql.DataSource/default"

我有:

   Looking up name="__/jdbc/nndb"
   Looking up binding for __ for context=null
   Looking up name="jdbc/nndb"
   Looking up binding for jdbc for context=__
   Looking up name="nndb"
   Looking up binding for nndb for context=jdbc
   InitialContextFactory.getInitialContext()
   Created initial context delegate for local namespace:org.mortbay.naming.local.localContextRoot@1830f66
   >>> new root context requested 
   Looking up name="comp/env"
   Looking up binding for comp for context=null
   Using classloader of current org.mortbay.jetty.handler.ContextHandler
   Looking up name="env"
   Looking up binding for env for context=comp
   Binding java:comp/env/jdbc/nndb to jdbc/nndb

话虽如此,整理一下您的类路径,并确保您正在运行6.1.11或6.1.26版本,而不是两个版本混合。这应该会解决问题。还有一件事,请确保您不要将任何自定义JNDI内容(例如对象工厂)带到WEB-INF/classes中。


如果相关的话,我的WEB-INF/lib目录下有以下文件: gwt-servlet.jar jetty-naming-6.1.11.jar jetty-plus-6.1.11.jar mysql-connector-java-5.1.17.jar slf4j-api-1.6.3.jar slf4j-jdk14-1.6.3.jar - Bill Compton
抱歉,我现在会查看您的日志。 - Pavel Veller
@BillCompton,请看一下更新后的答案。我想现在我已经用尽了我所有的远程调试选项。看看我的发现能否帮助你解决问题。 - Pavel Veller
Pavel!!我觉得你做到了!!我肯定还需要进行一些测试,并且需要仔细研究旧版本的启动器与你的新版本之间的差异,但是初步看起来,它能够正常运行!再次感谢你,无法用言语表达我的感激之情! - Bill Compton
@MrLister,我对StackOverflow的流程不是很熟悉,但我也要感谢您为我的问题设置赏金,帮助吸引了关注。谢谢! - Bill Compton
显示剩余4条评论

1
我可以向您展示在许多项目中为我们工作的配置。
1.) 使用gwt-dev依赖项创建XJettyLauncher:
package ru.minogin;

import java.io.File;

import org.mortbay.jetty.webapp.WebAppContext;

import com.google.gwt.core.ext.TreeLogger;

public class XJettyLauncher extends com.google.gwt.dev.shell.jetty.JettyLauncher {
    @SuppressWarnings("unchecked")
    @Override
    protected WebAppContext createWebAppContext(TreeLogger logger, File appRootDir) {
        WebAppContext context = new WebAppContext(appRootDir.getAbsolutePath(), "/");
        context.getInitParams().put("org.mortbay.jetty.servlet.Default.useFileMappedBuffer", "false");
        return context;
    }
}

将其打包为jar文件。

2.) 创建用户库Jetty并在其中包含:XJettyLauncher,jetty-naming-6.1.21.jar,jetty-plus-6.1.21.jar(或您的Jetty版本)。将此库添加到项目中。

3.) src/main/webapp/WEB-INF/jetty-web.xml:

   <?xml version="1.0"?>
    <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">

<Configure class="org.mortbay.jetty.webapp.WebAppContext">
    <New id="DB" class="org.mortbay.jetty.plus.naming.Resource">
        <Arg>java:comp/env/jdbc/DS</Arg>
        <Arg>
            <New class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource">
                <Set name="Url">jdbc:mysql://localhost:3306/database?autoReconnect=true&amp;zeroDateTimeBehavior=convertToNull&amp;characterEncoding=utf8
                </Set>
                <Set name="User">user</Set>
                <Set name="Password">passwd</Set>
            </New>
        </Arg>
    </New>
</Configure>

4.) pom.xml:

<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.19</version>
  <scope>runtime</scope>
</dependency>

5.) 运行配置:

-remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -port auto -war D:\var\ws\PROJECT\src\main\webapp -codeServerPort 9997 -server ru.minogin.XJettyLauncher ru.project.App


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接