Spring Boot voodoo 需要使用 DataNucleus 和 Hikari 实例化 JPA
Spring Boot voodoo required instantiating JPA with DataNucleus and Hikari
欢迎任何使此配置正常工作的帮助。
我正在尝试从 Spring Boot
接管自动连接池、数据源和 JPA 配置,以允许我将 DataNucleus
而不是 Hibernate
。
我的方法是在试错的基础上对 Boot
说缺失的部分进行编码。我不得不删除 Hibernate 依赖项以允许 DataNucleus 运行.
也许我现在编码太多或者我还不够。
Spring 因错误而失败:
Exception encountered during context initialization - cancelling refresh attempt:
[huge SNIP]
nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [org.springframework.data.repository.support.Repositories]:
Factory method 'repositories' threw exception;
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'symbolRepositoryImpl':
Unsatisfied dependency expressed through field 'entityManager';
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'javax.persistence.EntityManager' available:
expected single matching bean but found 2:
org.springframework.orm.jpa.SharedEntityManagerCreator#0,
org.springframework.orm.jpa.SharedEntityManagerCreator#1
[SNIP]
2017-06-01 09:43:09.675 ERROR 9108 --- [ restartedMain] o.s.b.d.LoggingFailureAnalysisReporter
***************************
APPLICATION FAILED TO START
***************************
Description:
Field entityManager in com.bp.gis.tardis.repository.SymbolRepositoryImpl
required a single bean, but 2 were found:
- org.springframework.orm.jpa.SharedEntityManagerCreator#0: defined by method 'createSharedEntityManager' in null
- org.springframework.orm.jpa.SharedEntityManagerCreator#1: defined by method 'createSharedEntityManager' in null
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
我可以花几个小时进一步调试,但断点出现在应该注入 entityManager 的存储库之一的初始化中。
这是我手动实例化的:
@Configuration
@EnableJpaRepositories(
basePackages = {"org.adam.repository"}
)
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "adam.datasource")
public AdamDataSourceProperties getDataSourceProperties() {
return new AdamDataSourceProperties();
}
@Bean
public DataSource getDataSource() {
AdamDataSourceProperties props = getDataSourceProperties();
return new HikariDataSource(props.getHikariConfig());
}
@Bean
public LocalContainerEntityManagerFactoryBean getEmfBean() {
LocalContainerEntityManagerFactoryBean emfBean =
new LocalContainerEntityManagerFactoryBean();
emfBean.setDataSource(getDataSource());
emfBean.setPersistenceUnitName("adam");
return emfBean;
}
@Bean
public EntityManagerFactory getEmf() {
LocalContainerEntityManagerFactoryBean emfBean = getEmfBean();
return emfBean.getNativeEntityManagerFactory();
}
}
我的 AdamDatasourceProperties
由 Spring 使用 application.properties
中的 "adam.datasource" 前缀值初始化,然后它可以创建一个 HikariConfig
对象以用于实例化 HikariDataSource
。这一点实际上很好,可能是实体管理器工厂导致了问题——或者其他问题。
我没有证据表明我的最后一个方法 getEmf()
确实有用。
此外,我怀疑错误
Required a single bean, but 2 were found
或者建议的操作很有帮助 - 我不想进入 Spring 源代码以便将 Spring 的 SharedEntityManagerCreator
上的其中一种方法注释为 @Primary
.
更新
DataNucleus
不会 运行 如果它在类路径上找到其他 JPA API 类 - 它坚持自己的持久性版本 API - 因此删除需要 Hibernate 包。
Caused by: org.datanucleus.exceptions.NucleusUserException:
Found Meta-Data for class org.adam.entity.TimeSeriesEntity
but this class is either not enhanced or you have multiple copies
of the persistence API jar in your CLASSPATH!!
Make sure all persistable classes are enhanced before running
DataNucleus and/or the CLASSPATH is correct.
at org.datanucleus.metadata.MetaDataManagerImpl
.initialiseClassMetaData(MetaDataManagerImpl.java:2814)
所以我从 spring-boot-starter-data-jpa
中排除了 Hibernate,错误消失了。
我将 LocalContainerEntityManagerFactoryBean
方法名称更改为 entityManagerFactory
:
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean emfBean =
new LocalContainerEntityManagerFactoryBean();
emfBean.setDataSource(getDataSource());
emfBean.setPersistenceUnitName("adam");
return emfBean;
}
为了启用测试,我必须复制此 @Configuration
class 并更改 EMF 方法以接受 Spring 的测试数据库:
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
@Qualifier("dataSource") DataSource dataSource) {
LocalContainerEntityManagerFactoryBean emfBean =
new LocalContainerEntityManagerFactoryBean();
emfBean.setDataSource(dataSource);
emfBean.setPersistenceUnitName("adam");
return emfBean;
}
@Qualifier
是为了 Intellij,其 Spring facet 抱怨这里有 2 个候选注入。
我还发现,使用此配置,EntityManager
的 repository/DTO 依赖注入不适用于 @Autowired
。它必须是本机 JPA 注释:
@PersistenceContext
private EntityManager entityManager;
使用我之前的 Hibernate 和 OpenJPA 配置,Spring 很高兴在 @Autowire
存在的情况下注入自己的实例化 EntityManager
。
这让我对 Spring 感到不满。它经常不按照罐头上说的做。 Spring 测试应该在包层次结构中找到 @Configuration
classes,但没有——我需要使用 @Import
。 Spring 还应该根据类型(EntityManager
、DataSource
等)找到依赖注入候选者,但它不会——在某些情况下,它们必须由命名为特定名称的方法或使用@Bean
声明名称的注释。
不过,完成了。
欢迎任何使此配置正常工作的帮助。
我正在尝试从 Spring Boot
接管自动连接池、数据源和 JPA 配置,以允许我将 DataNucleus
而不是 Hibernate
。
我的方法是在试错的基础上对 Boot
说缺失的部分进行编码。我不得不删除 Hibernate 依赖项以允许 DataNucleus 运行.
也许我现在编码太多或者我还不够。
Spring 因错误而失败:
Exception encountered during context initialization - cancelling refresh attempt:
[huge SNIP]
nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [org.springframework.data.repository.support.Repositories]:
Factory method 'repositories' threw exception;
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'symbolRepositoryImpl':
Unsatisfied dependency expressed through field 'entityManager';
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'javax.persistence.EntityManager' available:
expected single matching bean but found 2:
org.springframework.orm.jpa.SharedEntityManagerCreator#0,
org.springframework.orm.jpa.SharedEntityManagerCreator#1
[SNIP]
2017-06-01 09:43:09.675 ERROR 9108 --- [ restartedMain] o.s.b.d.LoggingFailureAnalysisReporter
***************************
APPLICATION FAILED TO START
***************************
Description:
Field entityManager in com.bp.gis.tardis.repository.SymbolRepositoryImpl
required a single bean, but 2 were found:
- org.springframework.orm.jpa.SharedEntityManagerCreator#0: defined by method 'createSharedEntityManager' in null
- org.springframework.orm.jpa.SharedEntityManagerCreator#1: defined by method 'createSharedEntityManager' in null
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
我可以花几个小时进一步调试,但断点出现在应该注入 entityManager 的存储库之一的初始化中。
这是我手动实例化的:
@Configuration
@EnableJpaRepositories(
basePackages = {"org.adam.repository"}
)
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "adam.datasource")
public AdamDataSourceProperties getDataSourceProperties() {
return new AdamDataSourceProperties();
}
@Bean
public DataSource getDataSource() {
AdamDataSourceProperties props = getDataSourceProperties();
return new HikariDataSource(props.getHikariConfig());
}
@Bean
public LocalContainerEntityManagerFactoryBean getEmfBean() {
LocalContainerEntityManagerFactoryBean emfBean =
new LocalContainerEntityManagerFactoryBean();
emfBean.setDataSource(getDataSource());
emfBean.setPersistenceUnitName("adam");
return emfBean;
}
@Bean
public EntityManagerFactory getEmf() {
LocalContainerEntityManagerFactoryBean emfBean = getEmfBean();
return emfBean.getNativeEntityManagerFactory();
}
}
我的 AdamDatasourceProperties
由 Spring 使用 application.properties
中的 "adam.datasource" 前缀值初始化,然后它可以创建一个 HikariConfig
对象以用于实例化 HikariDataSource
。这一点实际上很好,可能是实体管理器工厂导致了问题——或者其他问题。
我没有证据表明我的最后一个方法 getEmf()
确实有用。
此外,我怀疑错误
Required a single bean, but 2 were found
或者建议的操作很有帮助 - 我不想进入 Spring 源代码以便将 Spring 的 SharedEntityManagerCreator
上的其中一种方法注释为 @Primary
.
更新
DataNucleus
不会 运行 如果它在类路径上找到其他 JPA API 类 - 它坚持自己的持久性版本 API - 因此删除需要 Hibernate 包。
Caused by: org.datanucleus.exceptions.NucleusUserException:
Found Meta-Data for class org.adam.entity.TimeSeriesEntity
but this class is either not enhanced or you have multiple copies
of the persistence API jar in your CLASSPATH!!
Make sure all persistable classes are enhanced before running
DataNucleus and/or the CLASSPATH is correct.
at org.datanucleus.metadata.MetaDataManagerImpl
.initialiseClassMetaData(MetaDataManagerImpl.java:2814)
所以我从 spring-boot-starter-data-jpa
中排除了 Hibernate,错误消失了。
我将 LocalContainerEntityManagerFactoryBean
方法名称更改为 entityManagerFactory
:
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean emfBean =
new LocalContainerEntityManagerFactoryBean();
emfBean.setDataSource(getDataSource());
emfBean.setPersistenceUnitName("adam");
return emfBean;
}
为了启用测试,我必须复制此 @Configuration
class 并更改 EMF 方法以接受 Spring 的测试数据库:
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
@Qualifier("dataSource") DataSource dataSource) {
LocalContainerEntityManagerFactoryBean emfBean =
new LocalContainerEntityManagerFactoryBean();
emfBean.setDataSource(dataSource);
emfBean.setPersistenceUnitName("adam");
return emfBean;
}
@Qualifier
是为了 Intellij,其 Spring facet 抱怨这里有 2 个候选注入。
我还发现,使用此配置,EntityManager
的 repository/DTO 依赖注入不适用于 @Autowired
。它必须是本机 JPA 注释:
@PersistenceContext
private EntityManager entityManager;
使用我之前的 Hibernate 和 OpenJPA 配置,Spring 很高兴在 @Autowire
存在的情况下注入自己的实例化 EntityManager
。
这让我对 Spring 感到不满。它经常不按照罐头上说的做。 Spring 测试应该在包层次结构中找到 @Configuration
classes,但没有——我需要使用 @Import
。 Spring 还应该根据类型(EntityManager
、DataSource
等)找到依赖注入候选者,但它不会——在某些情况下,它们必须由命名为特定名称的方法或使用@Bean
声明名称的注释。
不过,完成了。