I m newbie on the spring and I m just testing some utilities to learn java configuration on the spring framework,so question is
I have two configuration as seen below and I want to extend one configuration to another and use sub java configuration with appconfig so I did this way and working everything good but I m still feeling its not good approach for me ,could you give me correct way on this or alternative of this thanks
Hibernate Configuration
**package configuration**
#Configuration
#EnableTransactionManagement
#ComponentScan({"configuration"})
#PropertySource(value={"classpath:application.properties"})
public class HibernateConfiguration {
#Autowired
Environment environment;
#Bean
public LocalSessionFactoryBean sessionFactory(){
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(generateDataSource());
sessionFactoryBean.setPackagesToScan(new String[]{"whateverpackage.model"});
sessionFactoryBean.setHibernateProperties(generateProperties());
return sessionFactoryBean;
}
#Bean
public DataSource generateDataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverclassname"));
driverManagerDataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
driverManagerDataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
driverManagerDataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
return driverManagerDataSource;
}
public Properties generateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
return properties;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager transactionManager = new HibernateTransactionManager(sessionFactory); //constructor-arg can be use in xml
return transactionManager;
}
}
SubConfiguration
package another.configuration
#Configuration
#ComponentScan({"another.configuration"})
#EnableTransactionManagement
#PropertySource(value={"classpath:application.properties"})
public class SubConfiguration extends HibernateConfiguration{
}
AppConfig
package another.configuration
#Configuration
#ComponentScan(basePackages="root package")
#Import(SubConfiguration.class)
public class AppConfig {
}
Related
I'm currently learning Spring and Hibernate. I have a StudentDAOImpl class that contains all my database queries. I want to get an instance of this bean in my main function and run the query methods there all in my main function for testing. I'm trying to do this by calling the getBean() method because the name of the bean is the class but first letter is lowercase if I'm not mistaken. The compiler is giving me this error
Exception in thread "main org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'studentDAOImpl' available**
Why can't Spring find my StudentDAOImpl bean? Thank you for your time in reading this post.
Here's my code
Main Function
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AnimalConfig.class,HibernateConfig.class); // Makes the sessionFactory bean known to the IOC
StudentDAOImpl student = (StudentDAOImpl)ctx.getBean("studentDAOImpl");
Student aStudent = new Student("dasdasdas","dasdadas","dsadasdasda#gmail.com");
student.addStudent(aStudent);
(( ConfigurableApplicationContext )ctx).close(); //Close the applicationContext
SpringApplication.run(DemoApplication.class, args);
}
StudentDAOImpl Class
#Repository //Sets up componenent scanning for DI for our services
public class StudentDAOImpl implements StudentDAO{
#Autowired
SessionFactory sessionFactory;
//Queries Ommited from post for space saving purposes
}
HibernateConfiguration File
#Configuration
#EnableTransactionManagement
public class HibernateConfig {
#Bean(name = "sessionFactory")
#Scope("singleton")
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(packagesToScan());
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/demo");
dataSource.setUsername("root");
dataSource.setPassword("danielL45");
return dataSource;
}
#Bean
public PlatformTransactionManager hibernateTransactionManager() {
HibernateTransactionManager transactionManager
= new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
private String[] packagesToScan(){
return new String[] {
"com.example.demo.Entities.Student"
};
}
private final Properties hibernateProperties() {
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "update");
hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
hibernateProperties.setProperty("current_session_context_class", "thread");
return hibernateProperties;
}
}
Use this:
StudentDAOImpl student = ctx.getBean(StudentDAOImpl.class)
This is a more secure way to get the bean that we need, since we may have only one bean with this class, using a string to select a Spring Bean has a propability of not working when not writing the name correctly.
When I am trying to use multiple datasources in my Spring Boot Application, every entityManager is creating unwanted tables from other datasources. How can I fix this?
Here's related snippet of my code:
dataSourceConfig.java
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef= "entityManagerFactory",
basePackages= {"com.wnp.customerinfo.customerinfo.customerrepository"},transactionManagerRef="transactionManager")
public class CustomerConfig {
#Bean(name="datasource")
#ConfigurationProperties(prefix="spring.customer.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name="entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(EntityManagerFactoryBuilder builder,
#Qualifier("datasource") DataSource dataSource) {
Map<String,Object> properties = new HashMap<>();
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
properties.put("hibernate.hbm2ddl.auto", "update");
return builder.dataSource(dataSource).properties(properties)
.packages("com.ecom.customerinfo.customerinfo.model").persistenceUnit("CustomerInfo").build();
}
#Bean(name="transactionManager")
public PlatformTransactionManager transactionManager(#Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
}
application.properties
spring.customer.datasource.jdbcUrl=jdbc:mysql://localhost:3306/customer_info_db_temp
spring.customer.datasource.username=root
spring.customer.datasource.password=
spring.prod.datasource.jdbcUrl=jdbc:mysql://localhost:3307/prod_info_db_temp
spring.prod.datasource.username=root
spring.prod.datasource.password=
The configuration you used in the class is perfect. But if you have all the model classes in the same package and giving the same base-package in all the configuration classes it will always create the empty tables in all the databases. Try to keep them in different packages.
Good evening,
what is the correct and common approach of handling two or more databases?
Consider this HibernateConfiguration class configuring only one datasource:
#Configuration #EnableTransactionManagement
#PropertySource(value = { "classpath:hibernate.properties" })
public class HibernateConfiguration {
#Autowired
private Environment env;
#Bean
public DataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
// ... setting data source
return dataSource;
}
private Properties getHibernateProperties() {
Properties properties = new Properties();
// ... setting Hibernate properties
return properties;
}
#Bean
public LocalSessionFactoryBean getSessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(getDataSource());
sessionFactory.setPackagesToScan(new String[] { "POJOs'" });
sessionFactory.setHibernateProperties(getHibernateProperties());
return sessionFactory;
}
#Bean public HibernateTransactionManager transactionManager(SessionFactory sf) {
HibernateTransactionManager htm = new HibernateTransactionManager();
htm.setSessionFactory(sf);
return htm;
}
}
Is recommended to let one class configure one datasource? Or is enough to configure all at once? How do I specify in Dao class which SessionFactory will be used and what is the recommended approach in case of switching two exact same databases on two different hosting servers?
The example DAOs. First I need to switch between Foo and Bar.
#Repository
public class RepositoryImpl implements RepositoryDao {
#Autowired // Here I need to switch between databases "foo" and "bar"
private SessionFactory sessionFactory;
...
The second one I need fixed on example database Foo.
#Repository
public class FooImpl implements FooDao {
#Autowired // Here I need fixed on "Foo"
private SessionFactory sessionFactory;
One approach
#Bean
#Primary
#ConfigurationProperties("app.datasource.foo")
public DataSourceProperties fooDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#Primary
#ConfigurationProperties("app.datasource.foo")
public DataSource fooDataSource() {
return fooDataSourceProperties().initializeDataSourceBuilder().build();
}
#Bean
#ConfigurationProperties("app.datasource.bar")
public BasicDataSource barDataSource() {
return (BasicDataSource) DataSourceBuilder.create()
.type(BasicDataSource.class).build();
}
Spring multiple datasources config
Other approach could be : loading different mapping (orm.xml) from persistence.xml or refer to different schemas in Entity classes.
I have a library that contains a few objects I would like to save in my database using hibernate.
I ended up making hbm.xml files for every single object. Now I have my AppConfig class
#Configuration
#ComponentScan("some.company")
#EnableAutoConfiguration(exclude = HibernateJpaAutoConfiguration.class)
#EnableTransactionManagement
public class AppConfig
extends WebMvcConfigurerAdapter
{
#Bean(name = "dataSource")
public DataSource dataSource()
{
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/somedatabase");
dataSource.setUsername("user");
dataSource.setPassword("password");
return dataSource;
}
#Bean(name = "sessionFactory")
public LocalSessionFactoryBean sessionFactory()
{
LocalSessionFactoryBean localSession = new LocalSessionFactoryBean();
localSession.setDataSource(dataSource());
return localSession;
}
#Bean(name = "transactionManager")
public HibernateTransactionManager transactionManager()
{
return new HibernateTransactionManager(sessionFactory().getObject());
}
}
How do I point it to my newly created hbm.xml files?
Or if that is not possible, then how would I go about creating hibernate mapping for the objects to which I have no write access to?The only constraint is that I can not write my app config in xml, there is too much there that would not be movable to xml now.
Pragmatically, I would go for:
#Bean(name = "sessionFactory")
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean localSession = new LocalSessionFactoryBean();
localSession.setDataSource(dataSource());
localSession.setMappingResources("my.hmb.xml", "files.hbm.xml");
return localSession;
}
(when the hbm files reside in the root of class path - e.g. in src/main/resources)
I am using Spring 4.16. I want to parameterize my persistence data. This is my config right now:
#Configuration
#EnableTransactionManagement
public class PersistenceConfiguration {
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
entityManager.setDataSource(this.dataSource());
entityManager.setPackagesToScan(new String[] {"com.example.movies.domain"});
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
entityManager.setJpaVendorAdapter(vendorAdapter);
entityManager.setJpaProperties(this.properties());
return entityManager;
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/sarasa_db");
dataSource.setUsername("root");
dataSource.setPassword("mypassword");
return dataSource;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
private Properties properties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "update");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
properties.setProperty("hibernate.show_sql", "false");
return properties;
}
}
And i want to parameterize on my application.properties all things i can. First of all, i want to put in datasource properties (so as i was reading, is possible that spring builds my datasource automatically, but apparently that is only using JdbcTemplate...):
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/sarasa_db
spring.datasource.username=root
spring.datasource.password=mypassword
And, if it's possible, all the Properties's properties, which i couldn't find nothing in doc
Do you know how could i do it ?
EDIT
This is my DAO implementation
#Configuration
#Import(PersistenceConfiguration.class)
public class DAOConfiguration {
#PersistenceContext
private EntityManager entityManager;
#Bean
public ClientDAO clientDAO() {
SimpleJpaRepository<Client, String> support = this.getSimpleJpaRepository(Client.class);
return new MySQLClientDAO(support);
}
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Description("Hibernate repository helper")
protected <T> SimpleJpaRepository<T, String> getSimpleJpaRepository(Class<T> domainClass) {
return new SimpleJpaRepository<T, String>(domainClass, this.entityManager);
}
}
You could do something like this:
First define PropertySourcesPlaceholderConfigurer bean somewhere in your Spring configuration:
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer();
ppc.setLocation(new ClassPathResource("application.properties"));
return ppc;
}
This configuration assumes that application.properties file is placed at the root of your classpath.
After setting up the property placeholder configurer you can access the properties in your database configuration class like so:
#Configuration
#EnableTransactionManagement
public class PersistenceConfiguration {
#Value("${spring.datasource.url}")
private String jdbcUrl;
// ...
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(jdbcUrl);
// ...
}
}
If you want an easy way to parametrize all properties, you should take a look at Spring Boot. It uses the application.properties file to automatically create data source with those properties, and many other things. This is probably the automatic datasource creation you mentioned in your question.