Multi module Springboot
i am creating multi module springboot project in which i have common-library and admin service are different modules and common-library contains all entity and repository class and interface and admin-service is implementing common-library as a dependency, i have used gradle and when i build the project , its building successfully using \
"./gradlew clean build -x test"
and when i try to run admin-service module using
"./gradlew :admin-service:bootRun"
i got exception. can someone please help me to solve this. Please have a look at my code below.
//Admin service main class file.
package com.zaihamm.admin;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.scheduling.annotation.EnableAsync;
@EnableAsync
@SpringBootApplication(scanBasePackages = "com.zaihamm.common", exclude =
{DataSourceAutoConfiguration.class })
@EntityScan("com.zaihamm.common.entity")
@EnableJpaRepositories(basePackages = {"com.zaihamm.common.repository"})
public class AdminServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AdminServiceApplication.class, args);
}
}
and common-library is like
My Admin service gradle is like this
and when i run i got this exception
Exception encountered during context initialization - cancelling
refresh attempt:
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'addressRepository' defined in
com.zaihamm.common.repository.AddressRepository defined in
@EnableJpaRepositories declared on AdminServiceApplication:
Cannot create inner bean '(inner bean)#35ef439e' of type
[org.springframework.orm.jpa.SharedEntityManagerCreator] while
setting bean property 'entityManager'; nested exception is
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name '(inner bean)#35ef439e': Cannot resolve
reference to bean 'entityManagerFactory' while setting
constructor argument; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No bean named 'entityManagerFactory' available
In your AdminServiceApplication class you have excluded DataSourceAutoConfiguration.class. That is probably the cause you are having missing entity manager. You'll have to configure your own custom dataSource class and then inject it.
Follows an example that worked for me in the past when I needed 2 datasources and also needed to exclude DataSourceAutoConfiguration.class. You will have to modify it to make it work for you:
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "myEntityManagerFactory",
transactionManagerRef = "myTransactionManager",
basePackages = "com.example.my_package.repository"
)
public class MyDataSourceConfig {
@Autowired
private Environment env;
@Bean
@Primary
public LocalContainerEntityManagerFactoryBean myEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(customDataSource());
em.setPersistenceUnitName("myPU");
em.setPackagesToScan(new String[]{"com.example.main_package"});
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setDatabasePlatform(env.getProperty("spring.jpa.database-platform"));
vendorAdapter.setShowSql(Boolean.getBoolean(env.getProperty("spring.jpa.show-sql")));
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
properties.put("hibernate.physical_naming_strategy", env.getProperty("spring.jpa.hibernate.naming.physical-strategy"));
properties.put("hibernate.implicit-strategy", env.getProperty("spring.jpa.hibernate.naming.implicit-strategy"));
properties.put("hibernate.dialect", env.getProperty("spring.jpa.database-platform"));
em.setJpaPropertyMap(properties);
return em;
}
@Bean
@Primary
public DataSource customDataSource() {
return DataSourceBuilder.create()
.driverClassName(env.getProperty("spring.datasource.driver-class-name"))
.url(env.getProperty("spring.datasource.url"))
.username(env.getProperty("spring.datasource.username"))
.password(env.getProperty("spring.datasource.password"))
.build();
}
@Bean
@Primary
public PlatformTransactionManager myTransactionManager() {
JpaTransactionManager tm = new JpaTransactionManager();
tm.setEntityManagerFactory(myEntityManagerFactory().getObject());
return tm;
}
}
When I've used this, I've also excluded other spring classes:
DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class
If you want to inject entityManager manually you'll do someting like this:
@Autowired
@Qualifier("myEntityManagerFactory")
private EntityManager myEntityManager;
Here is another simpler example from spring-data github repository https://github.com/spring-projects/spring-data-examples/blob/main/jpa/multiple-datasources/src/main/java/example/springdata/jpa/multipleds/customer/CustomerConfig.java