2017-01-01 11 views
5

Я строй конфигурации JPA с множественной настойчивостью единицами с использованием различных в памяти источников данных, но конфигурация не удается разрешениями квалифицированных источника данных для объекта менеджер фабрики боба со следующей ошибкой:Spring загрузки @Qualifier не работают с источниками данными

*************************** 
APPLICATION FAILED TO START 
*************************** 

Description: 

Parameter 0 of method emfb in datasources.Application$PersistenceConfiguration required a single bean, but 2 were found: 
     - ds1: defined by method 'ds1' in class path resource [datasources/Application$PersistenceConfiguration.class] 
     - ds2: defined by method 'ds2' in class path resource [datasources/Application$PersistenceConfiguration.class] 


Action: 

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed 

Вот пример приложения

package datasources; 

import javax.persistence.EntityManager; 
import javax.persistence.PersistenceContext; 
import javax.persistence.PersistenceContextType; 
import javax.sql.DataSource; 
import javax.ws.rs.ApplicationPath; 
import javax.ws.rs.GET; 
import javax.ws.rs.Path; 
import org.apache.log4j.Logger; 
import org.glassfish.jersey.server.ResourceConfig; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.beans.factory.annotation.Qualifier; 
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 
import org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration; 
import org.springframework.boot.builder.SpringApplicationBuilder; 
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.ComponentScan; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.context.annotation.Primary; 
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; 
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; 
import org.springframework.stereotype.Component; 

@Configuration 
@EnableAutoConfiguration(exclude = { 
//  HibernateJpaAutoConfiguration.class, 
//  DataSourceAutoConfiguration.class 
     JtaAutoConfiguration.class 
}) 
@ComponentScan 
public class Application { 

    public static void main(String[] args) { 

     new SpringApplicationBuilder(Application.class) 
      .build() 
      .run(args); 
    } 

    @Component 
    @Path("/ds") 
    public static class DsApi { 

     private final static Logger logger = Logger.getLogger(DsApi.class); 

     @Autowired(required = false) 
     @Qualifier("ds1") 
     private DataSource ds; 

     @GET 
     public String ds() { 
      logger.info("ds"); 
      return ds.toString(); 
     } 
    } 

    @Component 
    @Path("/em") 
    public static class EmApi { 

     private final static Logger logger = Logger.getLogger(EmApi.class); 

     @PersistenceContext(unitName = "ds2", type = PersistenceContextType.TRANSACTION) 
     private EntityManager em; 

     @GET 
     public String em() { 
      logger.info("em"); 
      return em.toString(); 
     } 
    } 

    @Configuration 
    @ApplicationPath("/jersey") 
    public static class JerseyConfig extends ResourceConfig { 
     public JerseyConfig() { 
      register(DsApi.class); 
      register(EmApi.class); 
     } 
    } 

    @Configuration 
    public static class PersistenceConfiguration { 

     @Bean 
     @Qualifier("ds1") 
     public DataSource ds1() { 
      return new EmbeddedDatabaseBuilder().build(); 
     } 

     @Bean 
     @Qualifier("ds2") 
     public DataSource ds2() { 
      return new EmbeddedDatabaseBuilder().build(); 
     } 

     @Bean 
     @Primary 
     @Autowired 
     public LocalContainerEntityManagerFactoryBean emfb(@Qualifier("ds1") DataSource ds, EntityManagerFactoryBuilder emfb) { 
      return emfb.dataSource(ds) 
        .packages(Application.class) 
        .persistenceUnit("ds1") 
        .build(); 
     } 

     @Bean 
     @Autowired 
     public LocalContainerEntityManagerFactoryBean emfb2(@Qualifier("ds2") DataSource ds, EntityManagerFactoryBuilder emfb) { 
      return emfb.dataSource(ds) 
        .packages(Application.class) 
        .persistenceUnit("ds2") 
        .build(); 
     } 
    } 
} 
+0

Возможно, он не работает в статическом классе? – Patrick

+0

Не может быть, поскольку я попытался заменить эти компоненты DataSource произвольным типом, и зависимости были правильно решены. Также попытался вернуть вручную экземпляр DataSource (без построителя) с той же ошибкой. –

ответ

3

Объявите один из ваших DataSource как @Primary.

Также у вас есть 2 бобы того же типа - LocalContainerEntityManagerFactoryBean, декларируют один из них @Primary, а также, следующим образом:

@Configuration 
public static class PersistenceConfiguration { 

     @Bean 
     @Primary 
     public DataSource ds1() { 
      return new EmbeddedDatabaseBuilder().build(); 
     } 

     @Bean 
     public DataSource ds2() { 
      return new EmbeddedDatabaseBuilder().build(); 
     } 

     @Bean 
     @Primary 
     @Autowired 
     public LocalContainerEntityManagerFactoryBean emfb(@Qualifier("ds1") DataSource ds, EntityManagerFactoryBuilder emfb) { 
      return emfb.dataSource(ds) 
        .packages(DemoApplication.class) 
        .persistenceUnit("ds1") 
        .build(); 
     } 

     @Bean 
     @Autowired 
     public LocalContainerEntityManagerFactoryBean emfb2(@Qualifier("ds2") DataSource ds, EntityManagerFactoryBuilder emfb) { 
      return emfb.dataSource(ds) 
        .packages(DemoApplication.class) 
        .persistenceUnit("ds2") 
        .build(); 
     } 
} 
+0

Это впрыснет ds1 в emfb2, которому необходимо ds2 –

+0

Это не должно быть, поскольку мы указываем '@Qualifier (« ds2 »)' при создании 'emfb2' – Arpit

+2

Действительно, вы правы! Но почему Qualifier требует, чтобы Primary работал? Кроме того, почему одна и та же проводка отлично работала без Primary, если эти ds-методы вместо этого вернули какой-то другой тип (и, конечно, методы emfb реорганизованы для использования этого типа)? –

2

Ошибка указывает, что в какой-то момент в приложении, боб впрыскивается по типу DataSource и не квалифицируется по названию в этот момент.

Не имеет значения, что вы добавили @Qualifier в одном месте. Инъекция не удалась в некотором другом месте, которое не было квалифицировано. Это не ваша ошибка, потому что это место находится в Spring Boot DataSourceAutoConfiguration, который вы сможете увидеть в своей трассе стека, ниже той части, которую вы опубликовали.

Я бы порекомендовал вас за исключением DataSourceAutoConfiguration i.e. @SpringBootApplication(exclude = DataSourceAutoConfiguration.class). В противном случае эта конфигурация применяется только к компоненту, который вы создали @Primary. Если вы точно не знаете, что это такое, это может привести к тонким и неожиданным различиям в поведении между вашим DataSource.

0

Попробуйте объявить компоненты фаз источника данных вне статического класса. I.e непосредственно в Application.java

 Смежные вопросы

  • Нет связанных вопросов^_^