Spring 引导@Qualifier 不适用于数据源
Spring boot @Qualifier doesn't work with datasources
我正在使用不同的内存中数据源构建具有多个持久性单元的JPA配置,但配置无法解析合格的datasource for entity manager factory 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
这是示例应用程序
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();
}
}
}
将您的 DataSource
之一声明为 @Primary
。
你还有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();
}
}
错误表明在应用程序的某个时刻,一个 bean 被类型 DataSource
注入并且在那个时刻 没有被名称限定 。
在一个位置添加了@Qualifier
并不重要。注入在某些 other 不合格的位置失败。这不是你的错,因为那个位置在 Spring Boot 的 DataSourceAutoConfiguration
中,你应该能够在你的堆栈跟踪中看到,在你发布的那部分下面。
我建议排除 DataSourceAutoConfiguration
,即 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
。否则,此配置仅应用于您创建的 bean @Primary
。除非您确切地知道那是什么,否则它可能会导致您的 DataSource
之间的行为出现细微和意想不到的差异。
尝试在静态 class 之外声明数据源 bean。即直接在 Application.java
我正在使用不同的内存中数据源构建具有多个持久性单元的JPA配置,但配置无法解析合格的datasource for entity manager factory 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
这是示例应用程序
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();
}
}
}
将您的 DataSource
之一声明为 @Primary
。
你还有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();
}
}
错误表明在应用程序的某个时刻,一个 bean 被类型 DataSource
注入并且在那个时刻 没有被名称限定 。
在一个位置添加了@Qualifier
并不重要。注入在某些 other 不合格的位置失败。这不是你的错,因为那个位置在 Spring Boot 的 DataSourceAutoConfiguration
中,你应该能够在你的堆栈跟踪中看到,在你发布的那部分下面。
我建议排除 DataSourceAutoConfiguration
,即 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
。否则,此配置仅应用于您创建的 bean @Primary
。除非您确切地知道那是什么,否则它可能会导致您的 DataSource
之间的行为出现细微和意想不到的差异。
尝试在静态 class 之外声明数据源 bean。即直接在 Application.java