Spring-引导和多个数据库连接:自动装配服务不工作
Spring-boot & multiple database connections: autowire service does not work
我正在编写一个 Spring-boot 应用程序,它至少需要连接到 2 个数据库。
我每个数据库有 1 个项目来定义它们的域,每个数据库有 1 个项目来定义它们的服务,还有 1 个 Vaadin 项目用于 UI.
- a business domain entity sample
@Entity
@Table(name="T_PARAMETER")
public class Parameter extends BaseIdEntity implements Serializable {
@Column(name="par_cls")
@NotNull
private String parameterClass;
@Column(name="par_cd")
@NotNull
private String parameterCode;
@Column(name="par_lan")
@NotNull
private String language;
@Column(name="par_sht_val")
@NotNull
private String parameterValueShort;
@Column(name="par_lng_val")
@NotNull
private String parameterValueLong;
- a authentication domain entity sample
@Entity
@Table(name="t_user", schema="authenticate")
public class User extends BaseIdEntity implements Serializable {
@Id
@Column(name="user_cd")
private String userCode;
@Column(name="pwd")
@NotNull
private String password;
@Column(name="new_pwd_req")
@NotNull
private boolean passwordRequired;
@Column(name="acc_lck")
@NotNull
private boolean accountLocked;
There are repositories onto these 2 entities beans, they just extends the JpaRepository as hereunder:
public interface ParameterRepository extends JpaRepository<Parameter,Integer>{}
服务定义如下:
@Service
@Transactional(transactionManager="authenticateTransactionManager")
public class ServiceParameterImpl implements ServiceParameter {
private final static Logger log = LoggerFactory.getLogger(ServiceParameterImpl.class);
@Autowired
private ParameterRepository parameterRepository;
@Override
@Transactional(readOnly=true,transactionManager="authenticateTransactionManager")
public List<Parameter> findParameterHeader(String filter) {
.../...
客户端应用为:
@SpringBootApplication
@Configuration
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class
, HibernateJpaAutoConfiguration.class
, DataSourceTransactionManagerAutoConfiguration.class })
@ComponentScan(
basePackages= {
"org.associative.ui"
,"org.associative.service"
})
@Import({AssociativityConfiguration.class, AuthenticateConfiguration.class})
public class Application {
private final static Logger log = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
和配置:
@Configuration
@EnableTransactionManagement
@EntityScan(basePackages= "org.associative.domain.associativity")
@EnableJpaRepositories(
basePackages = "org.associative.domain.associativity.repository"
, entityManagerFactoryRef = "associativityEntityManager"
, transactionManagerRef = "associativityTransactionManager"
)
@ConfigurationProperties(prefix = "db.associativity")
public class AssociativityConfiguration {
private final static Logger log = LoggerFactory.getLogger(AssociativityConfiguration.class);
@Autowired
private Environment env;
private final static String ASSOCIATIVITY_DRIVER_CLASS_NAME = "db.associativity.classname";
private final static String ASSOCIATIVITY_URL = "db.associativity.connectionUrl";
private final static String ASSOCIATIVITY_USERNAME = "db.associativity.username";
private final static String ASSOCIATIVITY_PASSWORD = "db.associativity.password";
private final static String HIBERNATE_DIALECT = "hibernate.dialect";
@Bean(name = "associativityDataSource")
public DataSource datasource() {
DataSource dataSource = DataSourceBuilder.create()
.driverClassName(env.getProperty(ASSOCIATIVITY_DRIVER_CLASS_NAME))
.url(env.getProperty(ASSOCIATIVITY_URL))
.username(env.getProperty(ASSOCIATIVITY_USERNAME))
.password(env.getProperty(ASSOCIATIVITY_PASSWORD)).build();
if (log.isTraceEnabled())
log.trace(String.format("associativityConfiguration datasource:%s", dataSource.toString()));
return dataSource;
}
@Bean(name = "associativityEntityManager")
@PersistenceContext(unitName = "associativity")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
EntityManagerFactoryBuilder builder,
@Qualifier("associativityDataSource") DataSource dataSource) {
Map<String, Object> jpaProperties = new HashMap<>();
jpaProperties.put(HIBERNATE_DIALECT, env.getProperty(HIBERNATE_DIALECT));
LocalContainerEntityManagerFactoryBean em = builder.dataSource(dataSource)
.packages("org.associative.domain.authenticate").persistenceUnit("pu_associativity").properties(jpaProperties)
.build();
em.setJpaPropertyMap(jpaProperties);
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(adapter); // not mandatory definition
return em;
}
@Bean(name = "associativityTransactionManager")
public PlatformTransactionManager associativityTransactionManager(
@Qualifier("associativityEntityManager") EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
}
和
@Configuration
@EnableTransactionManagement
@EntityScan(basePackages= "org.associative.domain.authenticate")
@EnableJpaRepositories(
basePackages = "org.associative.domain.authenticate.repository"
, entityManagerFactoryRef = "authenticateEntityManager"
, transactionManagerRef = "authenticateTransactionManager"
)
@ConfigurationProperties(prefix="db.authenticate")
public class AuthenticateConfiguration {
private final static Logger log = LoggerFactory.getLogger(AuthenticateConfiguration.class);
@Autowired
private Environment env;
private final static String AUTHENTICATE_DRIVER_CLASS_NAME= "db.authenticate.classname";
private final static String AUTHENTICATE_URL = "db.authenticate.connectionUrl";
private final static String AUTHENTICATE_USERNAME = "db.authenticate.username";
private final static String AUTHENTICATE_PASSWORD = "db.authenticate.password";
private final static String HIBERNATE_DIALECT = "hibernate.dialect";
@Primary
@Bean(name = "authenticateDataSource")
public DataSource datasource() {
DataSource dataSource = DataSourceBuilder.create()
.driverClassName(env.getProperty(AUTHENTICATE_DRIVER_CLASS_NAME))
.url(env.getProperty(AUTHENTICATE_URL))
.username(env.getProperty(AUTHENTICATE_USERNAME))
.password(env.getProperty(AUTHENTICATE_PASSWORD))
.build();
if ( log.isTraceEnabled()) log.trace(String.format("authenticateDataSource datasource:%s", dataSource.toString()));
return dataSource;
}
@Primary
@Bean(name="authenticateEntityManager")
@PersistenceContext(unitName = "authenticate")
//https://raymondhlee.wordpress.com/tag/enablejparepositories/
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
EntityManagerFactoryBuilder builder, @Qualifier("authenticateDataSource")DataSource dataSource) {
Map<String,Object> jpaProperties = new HashMap<>();
jpaProperties.put(HIBERNATE_DIALECT, env.getProperty(HIBERNATE_DIALECT));
LocalContainerEntityManagerFactoryBean em = builder
.dataSource(dataSource)
.packages("org.associative.domain.authenticate")
.persistenceUnit("pu_authenticate")
.properties(jpaProperties)
.build();
em.setJpaPropertyMap(jpaProperties);
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(adapter); // not mandatory definition
return em;
}
@Primary
@Bean(name="authenticateTransactionManager")
public PlatformTransactionManager authenticateTransactionManager(
@Qualifier("authenticateEntityManager")EntityManagerFactory entityManagerFactory){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
}
在构建客户端界面时使用自动装配构建服务时,我遇到了一个问题:
@SpringUI
public class ParameterListView 扩展 CssLayout 实现 Serializable {
private final static Logger log = LoggerFactory.getLogger(ParameterListView.class);
@Autowired
private ParameterController controller;
@PostConstruct
private void initView() {
if ( log.isTraceEnabled() ) log.trace(String.format("initView:%s", "no param"));
Grid<Parameter> grid = new Grid<>();
this.addComponent(grid);
grid.setItems(controller.getParameterHeader(""));
grid.addColumn(Parameter::getParameterClass);
grid.addColumn(Parameter::getParameterValueShort);
grid.addColumn(Parameter::getParameterValueLong);
2017-12-01 14:20:07.151 ERROR o.s.b.SpringApplication Application startup failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'parameterControllerImpl': Unsatisfied
dependency expressed through field 'serviceParameter'; nested
exception is
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'serviceParameterImpl': Unsatisfied
dependency expressed through field 'parameterRepository'; nested
exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'parameterRepository': Invocation of
init method failed; nested exception is
java.lang.IllegalArgumentException: Not a managed type: class
org.associative.domain.associativity.Parameter
我已经花了很多时间来解决多个数据库连接,因为我认为这个问题来自定义问题,但我现在不确定。
那么,为了解决这个问题,我应该注意什么。
非常感谢。
堆栈跟踪的最后一行是一个线索:Not a managed type: class org.associative.domain.associativity.Parameter
。 Hibernate 不知道您的 Parameter 实体。
在 LocalContainerEntityManagerFactoryBean
中,您将要扫描的包设置为 org.associative.domain.authenticate
。您的参数实体不在此包下。
这应该可以解决问题:
.packages("org.associative.domain.authenticate", "org.associative.domain.associativity")
我正在编写一个 Spring-boot 应用程序,它至少需要连接到 2 个数据库。 我每个数据库有 1 个项目来定义它们的域,每个数据库有 1 个项目来定义它们的服务,还有 1 个 Vaadin 项目用于 UI.
- a business domain entity sample
@Entity
@Table(name="T_PARAMETER")
public class Parameter extends BaseIdEntity implements Serializable {
@Column(name="par_cls")
@NotNull
private String parameterClass;
@Column(name="par_cd")
@NotNull
private String parameterCode;
@Column(name="par_lan")
@NotNull
private String language;
@Column(name="par_sht_val")
@NotNull
private String parameterValueShort;
@Column(name="par_lng_val")
@NotNull
private String parameterValueLong;
- a authentication domain entity sample
@Entity
@Table(name="t_user", schema="authenticate")
public class User extends BaseIdEntity implements Serializable {
@Id
@Column(name="user_cd")
private String userCode;
@Column(name="pwd")
@NotNull
private String password;
@Column(name="new_pwd_req")
@NotNull
private boolean passwordRequired;
@Column(name="acc_lck")
@NotNull
private boolean accountLocked;
There are repositories onto these 2 entities beans, they just extends the JpaRepository as hereunder:
public interface ParameterRepository extends JpaRepository<Parameter,Integer>{}
服务定义如下:
@Service @Transactional(transactionManager="authenticateTransactionManager") public class ServiceParameterImpl implements ServiceParameter { private final static Logger log = LoggerFactory.getLogger(ServiceParameterImpl.class); @Autowired private ParameterRepository parameterRepository; @Override @Transactional(readOnly=true,transactionManager="authenticateTransactionManager") public List<Parameter> findParameterHeader(String filter) {
.../...
客户端应用为:
@SpringBootApplication @Configuration @EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class , HibernateJpaAutoConfiguration.class , DataSourceTransactionManagerAutoConfiguration.class }) @ComponentScan( basePackages= { "org.associative.ui" ,"org.associative.service" }) @Import({AssociativityConfiguration.class, AuthenticateConfiguration.class}) public class Application { private final static Logger log = LoggerFactory.getLogger(Application.class); public static void main(String[] args) { SpringApplication.run(Application.class, args); }
}
和配置:
@Configuration @EnableTransactionManagement @EntityScan(basePackages= "org.associative.domain.associativity") @EnableJpaRepositories( basePackages = "org.associative.domain.associativity.repository" , entityManagerFactoryRef = "associativityEntityManager" , transactionManagerRef = "associativityTransactionManager" ) @ConfigurationProperties(prefix = "db.associativity") public class AssociativityConfiguration { private final static Logger log = LoggerFactory.getLogger(AssociativityConfiguration.class); @Autowired private Environment env; private final static String ASSOCIATIVITY_DRIVER_CLASS_NAME = "db.associativity.classname"; private final static String ASSOCIATIVITY_URL = "db.associativity.connectionUrl"; private final static String ASSOCIATIVITY_USERNAME = "db.associativity.username"; private final static String ASSOCIATIVITY_PASSWORD = "db.associativity.password"; private final static String HIBERNATE_DIALECT = "hibernate.dialect"; @Bean(name = "associativityDataSource") public DataSource datasource() { DataSource dataSource = DataSourceBuilder.create() .driverClassName(env.getProperty(ASSOCIATIVITY_DRIVER_CLASS_NAME)) .url(env.getProperty(ASSOCIATIVITY_URL)) .username(env.getProperty(ASSOCIATIVITY_USERNAME)) .password(env.getProperty(ASSOCIATIVITY_PASSWORD)).build(); if (log.isTraceEnabled()) log.trace(String.format("associativityConfiguration datasource:%s", dataSource.toString())); return dataSource; } @Bean(name = "associativityEntityManager") @PersistenceContext(unitName = "associativity") public LocalContainerEntityManagerFactoryBean entityManagerFactory( EntityManagerFactoryBuilder builder, @Qualifier("associativityDataSource") DataSource dataSource) { Map<String, Object> jpaProperties = new HashMap<>(); jpaProperties.put(HIBERNATE_DIALECT, env.getProperty(HIBERNATE_DIALECT)); LocalContainerEntityManagerFactoryBean em = builder.dataSource(dataSource) .packages("org.associative.domain.authenticate").persistenceUnit("pu_associativity").properties(jpaProperties) .build(); em.setJpaPropertyMap(jpaProperties); HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter(); em.setJpaVendorAdapter(adapter); // not mandatory definition return em; } @Bean(name = "associativityTransactionManager") public PlatformTransactionManager associativityTransactionManager( @Qualifier("associativityEntityManager") EntityManagerFactory entityManagerFactory) { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(entityManagerFactory); return transactionManager; }
}
和
@Configuration @EnableTransactionManagement @EntityScan(basePackages= "org.associative.domain.authenticate") @EnableJpaRepositories( basePackages = "org.associative.domain.authenticate.repository" , entityManagerFactoryRef = "authenticateEntityManager" , transactionManagerRef = "authenticateTransactionManager" ) @ConfigurationProperties(prefix="db.authenticate") public class AuthenticateConfiguration { private final static Logger log = LoggerFactory.getLogger(AuthenticateConfiguration.class); @Autowired private Environment env; private final static String AUTHENTICATE_DRIVER_CLASS_NAME= "db.authenticate.classname"; private final static String AUTHENTICATE_URL = "db.authenticate.connectionUrl"; private final static String AUTHENTICATE_USERNAME = "db.authenticate.username"; private final static String AUTHENTICATE_PASSWORD = "db.authenticate.password"; private final static String HIBERNATE_DIALECT = "hibernate.dialect"; @Primary @Bean(name = "authenticateDataSource") public DataSource datasource() { DataSource dataSource = DataSourceBuilder.create() .driverClassName(env.getProperty(AUTHENTICATE_DRIVER_CLASS_NAME)) .url(env.getProperty(AUTHENTICATE_URL)) .username(env.getProperty(AUTHENTICATE_USERNAME)) .password(env.getProperty(AUTHENTICATE_PASSWORD)) .build(); if ( log.isTraceEnabled()) log.trace(String.format("authenticateDataSource datasource:%s", dataSource.toString())); return dataSource; } @Primary @Bean(name="authenticateEntityManager") @PersistenceContext(unitName = "authenticate") //https://raymondhlee.wordpress.com/tag/enablejparepositories/ public LocalContainerEntityManagerFactoryBean entityManagerFactory( EntityManagerFactoryBuilder builder, @Qualifier("authenticateDataSource")DataSource dataSource) { Map<String,Object> jpaProperties = new HashMap<>(); jpaProperties.put(HIBERNATE_DIALECT, env.getProperty(HIBERNATE_DIALECT)); LocalContainerEntityManagerFactoryBean em = builder .dataSource(dataSource) .packages("org.associative.domain.authenticate") .persistenceUnit("pu_authenticate") .properties(jpaProperties) .build(); em.setJpaPropertyMap(jpaProperties); HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter(); em.setJpaVendorAdapter(adapter); // not mandatory definition return em; } @Primary @Bean(name="authenticateTransactionManager") public PlatformTransactionManager authenticateTransactionManager( @Qualifier("authenticateEntityManager")EntityManagerFactory entityManagerFactory){ JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(entityManagerFactory); return transactionManager; }
}
在构建客户端界面时使用自动装配构建服务时,我遇到了一个问题:
@SpringUI public class ParameterListView 扩展 CssLayout 实现 Serializable {
private final static Logger log = LoggerFactory.getLogger(ParameterListView.class); @Autowired private ParameterController controller; @PostConstruct private void initView() { if ( log.isTraceEnabled() ) log.trace(String.format("initView:%s", "no param")); Grid<Parameter> grid = new Grid<>(); this.addComponent(grid); grid.setItems(controller.getParameterHeader("")); grid.addColumn(Parameter::getParameterClass); grid.addColumn(Parameter::getParameterValueShort); grid.addColumn(Parameter::getParameterValueLong);
2017-12-01 14:20:07.151 ERROR o.s.b.SpringApplication Application startup failed org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'parameterControllerImpl': Unsatisfied
dependency expressed through field 'serviceParameter'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'serviceParameterImpl': Unsatisfied dependency expressed through field 'parameterRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'parameterRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a managed type: class org.associative.domain.associativity.Parameter
我已经花了很多时间来解决多个数据库连接,因为我认为这个问题来自定义问题,但我现在不确定。 那么,为了解决这个问题,我应该注意什么。
非常感谢。
堆栈跟踪的最后一行是一个线索:Not a managed type: class org.associative.domain.associativity.Parameter
。 Hibernate 不知道您的 Parameter 实体。
在 LocalContainerEntityManagerFactoryBean
中,您将要扫描的包设置为 org.associative.domain.authenticate
。您的参数实体不在此包下。
这应该可以解决问题:
.packages("org.associative.domain.authenticate", "org.associative.domain.associativity")