迁移到 Tomcat 8:InstanceAlreadyExistsException 数据源

Posted

技术标签:

【中文标题】迁移到 Tomcat 8:InstanceAlreadyExistsException 数据源【英文标题】:Migration to Tomcat 8: InstanceAlreadyExistsException datasource 【发布时间】:2015-04-02 10:44:33 【问题描述】:

我对 Tomcat 8 中的上下文配置有疑问。我将项目从 Tomcat 7 迁移到 8 并遇到异常问题:如果配置中没有任何变化,我发现了一个错误:

    "2015-02-03 12:05:48,310 FIRST_ADMIN ERROR web.context.ContextLoader:331 
-> Context initialization failed org.springframework.jmx.export.UnableToRegisterMBeanException: 
    Unable to register MBean [org.apache.tomcat.dbcp.dbcp2.BasicDataSource@434990dd]
     with key 'dataSource'; nested exception is 
    javax.management.InstanceAlreadyExistsException:  
    Catalina:type=DataSource,host=localhost,context=/first-
    admin,class=javax.sql.DataSource,name="jdbc/datasource/first"

部分上下文:

<Resource name="jdbc/datasource/first"
              auth="Container"
              type="javax.sql.DataSource"
              poolPreparedStatements="true"
              initialSize="25"
              maxActive="100"
              maxIdle="100"
              minIdle="25"
              username="us"
              password="pa"
              driverClassName="com.mysql.jdbc.Driver"
              validationQuery="select 1"
              testOnBorrow="true"
          url="jdbc:mysql://localhost:3306/firstproject?useUnicode=true&amp;characterEncoding=UTF-8&amp;profileSQL=false&amp;autoSlowLog=false&amp;slowQueryThresholdMillis=100&amp;autoReconnect=true"/>

所以,它在 tomcat 7 中运行没有任何问题。在 Tomcat 8 中,我可以通过 2 种方式解决这个问题:

    通过添加到资源:singleton = "false"; 通过添加到资源:factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"

如果我清楚地了解 tomcat 为我的应用程序和 jmx 创建数据源,但在 Tomcat 7 中它是单个对象,在 Tomcat 8 中它必须不同。所以我的问题是为什么会发生这种情况?我在文档中找不到有关此更改的任何信息。而且我很感兴趣什么更好:创建单个数据源(我认为是这样)或通过工厂创建多个。

【问题讨论】:

tomcat 7 (from) 和 tomcat 8 (to) 的版本是什么?您还可以添加您的 web.xml 吗?您的应用程序是否在其自己的 context.xml 文件 (META-INF) 中使用上述声明 - 如果是,您可以发布这个吗?顺便说一句,使用 JDBC 资源时,单例必须为“true” 【参考方案1】:

有一个聪明的简单方法可以避免这个问题。

将数据源定义放在生产服务器上某处的 application.properties 文件中。 例如:

datasource.driverClassName=com.mysql.jdbc.Driver
datasource.url=jdbc:mysql://localhost:3306/firstproject?useUnicode=true&amp;characterEncoding=UTF-8&amp;profileSQL=false&amp;autoSlowLog=false&amp;slowQueryThresholdMillis=100&amp;autoReconnect=true
datasource.username=us
etc..

并在 xml 上下文中添加这一行

<Environment name="spring.config.location" value="file:[path]\application.properties" type="java.lang.String"/>

在这里找到这个解决方案之前我一直在苦苦挣扎How to externalize application.properties in Tomcat webserver for Spring?

它会给你带来其他好处:

简单的弹簧配置 允许您使用嵌入式 tomcat 运行 webapp 如果您不小心将自己的 application.properties 打包到 war 文件中,生产 tomcat 将忽略它

【讨论】:

【参考方案2】:

我们遇到了同样的问题。我们将数据源声明为 spring bean,看起来 spring 和 bean 本身都试图注册一个导致此冲突的 Mbean。 我们所要做的就是像这样配置我们的 Mbean Exporter:

@Bean
public AnnotationMBeanExporter annotationMBeanExporter() 
    AnnotationMBeanExporter annotationMBeanExporter = new AnnotationMBeanExporter();
    annotationMBeanExporter.addExcludedBean("dataSource");
    return annotationMBeanExporter;

虽然我想将注册策略设置为:

annotationMBeanExporter.setRegistrationPolicy(RegistrationPolicy.IGNORE_EXISTING);

也许也可以。

【讨论】:

【参考方案3】:

如果有人使用 applicationContext.xml 样式,我解决了这样的问题:

<bean id="myNamedExporter" class="org.springframework.jmx.export.MBeanExporter">
    <property name="registrationPolicy" value="IGNORE_EXISTING" />
</bean>

【讨论】:

【参考方案4】:

如果您想要使用注释的解决方案 Spring boot 已经定义了 MBeanExporter bean,所以你可以自动连接它

@Autowired
MBeanExporter mBeanExporter ;

然后更改注册策略

mBeanExporter.setRegistrationPolicy(RegistrationPolicy.IGNORE_EXISTING);

【讨论】:

【参考方案5】:

我遇到了同样的错误,并通过将 registration="ignoreExisting" 添加到 mbean-export 部分来解决它:

<context:mbean-export server="mbeanServer" default-domain="mydomain" registration="ignoreExisting" />

【讨论】:

以上是关于迁移到 Tomcat 8:InstanceAlreadyExistsException 数据源的主要内容,如果未能解决你的问题,请参考以下文章

从 web.xml 迁移到基于 Java 的配置 - 无法启动 Tomcat 8

Tomcat 8 - LDAP:NameNotFoundException 错误代码 32,剩余名称为空字符串

Tomcat因项目迁移,启动窗口一闪而过,启动失败的解决办法。

在 Tomcat 6-Java 7/8 中运行 Tomcat 6-Java 6 WebApps

项目由tomcat迁移到TongWeb之后报java.lang.NoClassDefFoundError

从 Tomcat 6 JDK 1.6 迁移到 Tomcat 7 JDK 1.7 会话问题