Migration to Tomcat 8: InstanceAlreadyExistsException datasource
Asked Answered
H

5

26

I have a question about context config in Tomcat 8. I migrating project from Tomcat 7 to 8 and have unusual problem: if nothing change in config I caught an error:

    "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"

Part of context:

<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"/>

So, it's works in tomcat 7 without any problem. In Tomcat 8 I can solve this problem in 2 ways:

  1. By adding to resource: singleton = "false";
  2. By adding to resource: factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"

If I clearly understand tomcat creates datasource for my app and for jmx, but in Tomcat 7 it was single object, in Tomcat 8 it must be different. So my question is why that situation has happened? I couldn't find any information of this change in documentation. And I'm interesting what is better: create single datasource (I think so) or create several by factory.

Herzig answered 3/2, 2015 at 9:32 Comment(1)
What are the versions tomcat 7 (from) and tomcat 8 (to)? Can you also add your web.xml? Is your application using the above mentioned declaration in its own context.xml file (META-INF) - if so, can you post this? Btw when using a JDBC resource, singleton must be "true"Multicolor
S
12

We had the same problem. We declared our data source as a spring bean, and it looks like both spring and the bean itself try to register an Mbean which leads to this conflict. All we had to do is configure our Mbean Exporter like this:

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

Although I suppose setting the registration policy to:

annotationMBeanExporter.setRegistrationPolicy(RegistrationPolicy.IGNORE_EXISTING);

might also work.

Striking answered 22/4, 2016 at 13:16 Comment(0)
V
10

I had the same error and resolved it by adding registration="ignoreExisting" to the mbean-export part:

<context:mbean-export server="mbeanServer" default-domain="mydomain" registration="ignoreExisting" />
Versify answered 28/5, 2015 at 14:24 Comment(0)
L
5

If you want the solution using annotations Spring boot already defines MBeanExporter bean so you can auto-wire on it

@Autowired
MBeanExporter mBeanExporter ;

Then change the registration policy

mBeanExporter.setRegistrationPolicy(RegistrationPolicy.IGNORE_EXISTING);
Lamina answered 16/11, 2017 at 10:11 Comment(0)
C
2

If anybody uses applicationContext.xml style out there, I solved the issue like this:

<bean id="myNamedExporter" class="org.springframework.jmx.export.MBeanExporter">
    <property name="registrationPolicy" value="IGNORE_EXISTING" />
</bean>
Chestnut answered 17/7, 2018 at 20:14 Comment(0)
U
0

There is a smart easy way to avoid this problem.

Put the datasource definition instead in an application.properties file somewhere on the production server. eg:

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..

and add this line in the xml context

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

I have been struggling before finding this solution here How to externalize application.properties in Tomcat webserver for Spring?

It will bring you other advantages:

  • easy spring configuration
  • allows you the run the webapp with embedded tomcat
  • if you ever inadvertently package your own application.properties in the war file, it will be ignored by the production tomcat
Ungraceful answered 2/10, 2020 at 6:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.