Миграция на Tomcat 8: источник данных InstanceAlreadyExistsException

У меня вопрос по настройке контекста в 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 я могу решить эту проблему двумя способами:

  1. Добавляя в ресурс: singleton = "false";
  2. Добавляя в ресурс: factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"

Если я ясно понимаю, что tomcat создает источник данных для моего приложения и для jmx, но в Tomcat 7 это был один объект, в Tomcat 8 он должен быть другим. Итак, мой вопрос, почему такая ситуация произошла? Я не смог найти никакой информации об этом изменении в документации. И мне интересно, что лучше: создать один источник данных (я так думаю) или создать несколько на заводе.

4 ответа

У нас была такая же проблема. Мы объявили наш источник данных как 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);

может также сработать.

У меня была та же ошибка, и я решил ее, добавив registration="ignoreExisting" в часть экспорта mbean:

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

Если вы хотите, чтобы решение, использующее аннотации, Spring boot уже определяет bean- компонент MBeanExporter, так что вы можете автоматически подключиться к нему.

@Autowired
MBeanExporter mBeanExporter ;

Затем измените политику регистрации

mBeanExporter.setRegistrationPolicy(RegistrationPolicy.IGNORE_EXISTING);

Если кто-то использует стиль applicationContext.xml, я решил проблему следующим образом:

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

Есть умный простой способ избежать этой проблемы.

Вместо этого поместите определение источника данных в файл 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"/>

Я боролся, прежде чем найти это решение здесь. Как экстернализовать application.properties на веб-сервере Tomcat для Spring?

Это принесет вам и другие преимущества:

  • легкая конфигурация пружины
  • позволяет запускать веб-приложение со встроенным tomcat
  • если вы когда-нибудь случайно упакуете свое собственное application.properties в файл war, он будет проигнорирован производственным tomcat
Другие вопросы по тегам