Doubt regarding the management of JPA with Spring in JEE server

Asked

Viewed 377 times

3

I’m starting in Spring MVC and in the book I’m reading the configuration and management of connections is all done by Spring, IE, Spring opens and manages connections with the bank and makes it available as if I had in a JEE server (@PersistenceContext and @Transactional).

The point is that this is all done in a web container like Tomcat or Jetty, my doubt is how to manage this issue in a full JEE server like Wildfly, because I want the connection to be created by Wildfly (Datasource created in wildfly) and not by Spring

How does this integration work, I do not make any connection configuration of Spring and leave it to the server only, or I have to configure something in Spring so that it can take the datasource created by wildfly and it (spring) do the management? My doubt is also because there is a Spring filter that keeps the connections open throughout the request (org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter) and how it will manage this if the connections are managed by the JEE server (wildfly)?

I am using Spring 4.2 and configuring everything via Annotations, follows excerpt from the current configuration that works in a web container:

import java.util.Properties;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.env.Environment;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
public class JPAConfiguration {

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource);
        em.setPackagesToScan(new String[] { "br.com.casadocodigo.loja.models" });

        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(additionalProperties());

        return em;
    }

    @Bean   
    public DataSource dataSource(Environment environment){
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://192.168.56.200:3306/casadocodigo");
        dataSource.setUsername( "root" );
        dataSource.setPassword( "123456" );
        return dataSource;
    }

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf){
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(emf);     
        return transactionManager;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
        return new PersistenceExceptionTranslationPostProcessor();
    }

    Properties additionalProperties() {
        Properties properties = new Properties();
        properties.setProperty("hibernate.hbm2ddl.auto", "update");
        properties.setProperty("hibernate.show_sql", "true");
        return properties;
    }

}

2 answers

1

It is possible to lookup Datasource with JNDI.

There are two ways to do it programmatically.

public DataSource dataSource() {
    JndiDataSourceLookup lookup = new JndiDataSourceLookup();
    return lookup.getDataSource("jdni");
}

or

public DataSource dataSource() {
    DataSource ds = null;
    try {
        Context ctx = new InitialContext();
        ds = (DataSource) ctx.lookup("jdbc/nomeBanco");
    } catch (NamingException e) {
        e.printStackTrace();
    }
    return ds;
}

If using the JndiDataSourceLookup, take a look at the method setResourceRef, since the container is Java EE.

  • Thanks friend, it worked perfectly! Regarding setResourceRef I am putting the prefix, at least for now.

1

If what the container is managed for you is the data source, just change the way you recover the data source.

As opposed to using DriverManagerDataSource, which is a basic implementation of DataSource, you can recover the resource by JNDI resource published by container.

Starting from your configuration, just change the implementation of JPAConfiguration#dataSource for something like this:

@Bean
public DataSource dataSource() throws NamingException {
    final JndiTemplate jndi = new JndiTemplate();
    return jndi.lookup("${jndi.ds.name}", DataSource.class);
}

Or so:

@Bean
public DataSource dataSource() throws DataSourceLookupFailureException {
    return new JndiDataSourceLookup().getDataSource("${jndi.ds.name}");
}

This second way is more elegant, since it encapsulates the JndiTemplate for you, in addition to making other negotiations, such as trying other addresses in the JNDI.

In XML would look something like this:

<jee:jndi-lookup id="dataSource" jndi-name="${jndi.ds.name}" expected-type="javax.sql.DataSource" />

It is worth noting that your EntityManagerFactory can also be managed by the Java EE container and not by Spring, replacing the LocalContainerEntityManagerFactoryBean.

In this case the configuration will be a little different from the commonly used. Using Java configuration, it would be something like this:

@Bean
public EntityManagerFactory entityManagerFactory() throws NamingException {
    final JndiTemplate jndi = new JndiTemplate();
    return jndi.lookup("${jta.emf.jndi}", EntityManagerFactory.class);
}

@Bean
public TransactionFactory transactionManager(){
    return new JtaTransactionManager();
}

In XML would look something like this:

<!-- referência da EMF na JNDI -->
<jee:jndi-lookup id="entityManagerFactory" jndi-name="${jta.emf.jndi}" expected-type="javax.persistence.EntityManagerFactory" />

<!-- você deve falar que agora é JTA -->
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" />

In the latter case additional configuration may be required on the persistence unit and may break the portability Servlet container/full Jee container.

On the question of OpenEntityManagerInViewFilter regardless of how spring achieves a connection or if it is he who manages the connections, this filter has no knowledge of it, just that there is a bean in the context of Spring for the EntityManagerFactory (standard name of bean is entityManagerFactory) - and this can be both managed by it and recovered from JNDI and managed by the container.

Last remark is that if you configure your application well to run in one Servlet container will also manage to run it always no problem at a Jee container.

  • Thanks friend, working perfectly in management by Spring! I will test the unique container management approach for learning.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.