简体   繁体   English

Spring引导@Qualifier不适用于数据源

[英]Spring boot @Qualifier doesn't work with datasources

I'm building JPA configuration with multiple persistence units using different in-memory datasources , but the configuration fails resolving the qualified datasource for entity manager factory bean with the following error: 我正在使用不同的内存数据源构建具有多个持久性单元的 JPA配置,但配置无法解析实体管理器工厂bean的限定数据源 ,并出现以下错误:

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

Here is the sample application 这是示例应用程序

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();
        }
    }
}

The error is indicating that at some point in the application, a bean is being injected by the type DataSource and not being qualified by name at that point . 该错误表明在应用程序中的某些点,一个bean正被注入的类型DataSource ,而不是由名称在该点合格。

It does not matter that you have added @Qualifier in one location. 您在一个位置添加了@Qualifier并不重要。 The injection is failing in some other location that has not been qualified. 注射在其他尚未合格的位置失败。 It's not your fault though because that location is in Spring Boot's DataSourceAutoConfiguration which you should be able to see in your stack trace, below the piece that you have posted. 这不是你的错,因为该位置在Spring Boot的DataSourceAutoConfiguration ,您应该能够在堆栈跟踪中看到,在您发布的文件下方。

I would recommend excluding DataSourceAutoConfiguration ie @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) . 我建议排除DataSourceAutoConfiguration@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) Otherwise, this configuration is only being applied to the bean you have made @Primary . 否则,此配置仅应用于您创建的@Primary bean。 Unless you know exactly what that is, it is likely to result in subtle and unexpected differences in behaviour between your DataSource s. 除非您确切知道它是什么,否则很可能会导致DataSource之间行为的细微和意外差异。

Declare one of your DataSource as @Primary . 将您的一个DataSource声明为@Primary

Also you have 2 beans of same type - LocalContainerEntityManagerFactoryBean , declare one of them @Primary as well, as follows: 你也有2个相同类型的bean - 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();
        }
 }

Try declaring the datasource beans outside the static class . 尝试在静态类之外声明数据源bean。 Ie directly in Application.java 即直接在Application.java中

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM