Spring Data JPA + EclipseLink: Configurando Spring-Boot para usar EclipseLink como proveedor de JPA
Spring Data JPA
Publicación actualizada a fecha 2020-06-28.

Spring emplea Hibernate como proveedor de JPA por defecto. Aunque Hibernate es una buena elección, algunos preferimos emplear EclipseLink ya que en un principio se suponía que era la implementación de referencia para el JSR de Persistencia en Java.
En este tutorial mostraremos como configurar una aplicación Spring Boot para que use EclipseLink como capa de persistencia JPA para una base de datos H2 en memoria, aunque se podría emplear cualquier otro tipo de base de datos. Puedes encontrar el código fuente del artículo en GitHub.
Arreglando dependencias
Para poder emplear EclipseLink, es recomendable quitar el EntityManager de Hibernate del classpath para evitarnos colisiones. Para ello simplemente tenemos que añadir una exclusión en nuestro script de Gradle o en el fichero pom.xml
de Maven. Si estamos empleando alguna otra herramienta de compilación, no será necesario este paso (o será distinto).
1dependencies {
2 implementation ('org.eclipse.persistence:eclipselink:2.7.7')
3 implementation ('org.springframework.boot:spring-boot-starter-web')
4 implementation('org.springframework.boot:spring-boot-starter-actuator')
5 implementation('org.springframework.boot:spring-boot-starter-data-jpa'){
6 exclude group: 'org.hibernate', module: 'hibernate-core'
7 exclude group: 'org.hibernate.common', module: 'common-annotations'
8 }
9 //...Your project dependencies...
10}
En el código se muestra como añadir una exclusión en el script build.gradle de nuestro proyecto de ejemplo.
Configurando Spring
Para poder cambiar el proveedor JPA en Spring, tendremos que extender la clase JpaBaseConfiguration
y anotarla como una clase @Configuration
de Spring (CustomJpaConfiguration
).
1@Configuration
2@EnableTransactionManagement
3@EnableJpaRepositories("com.marcnuri.demo.springeclipselink.repository")
4public class CustomJpaConfiguration extends JpaBaseConfiguration {
5
6 protected CustomJpaConfiguration(DataSource dataSource, JpaProperties properties,
7 ObjectProvider<JtaTransactionManager> jtaTransactionManager) {
8 super(dataSource, properties, jtaTransactionManager);
9 }
10
11 @Override
12 protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
13 return new EclipseLinkJpaVendorAdapter();
14 }
15
16 @Override
17 protected Map<String, Object> getVendorProperties() {
18 final Map<String, Object> ret = new HashMap<>();
19 ret.put(PersistenceUnitProperties.BATCH_WRITING, BatchWriting.JDBC);
20 return ret;
21 }
22
23 @Bean("entityManagerFactory")
24 public LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactory(
25 EntityManagerFactoryBuilder builder, DataSource dataSource) {
26
27 return builder
28 .dataSource(dataSource)
29 .packages("com.marcnuri.demo.springeclipselink.repository")
30 .persistenceUnit("YourPersistenceUnitName")
31 .properties(initJpaProperties()).build();
32 }
33
34 @Bean
35 public static DataSource dataSource() {
36 final DriverManagerDataSource dataSource = new DriverManagerDataSource();
37 dataSource.setDriverClassName("org.h2.Driver");
38 dataSource.setUrl("jdbc:h2:mem:marcnuridemo;DB_CLOSE_DELAY=-1");
39 dataSource.setUsername("sa");
40 dataSource.setPassword("password");
41 return dataSource;
42 }
43
44 @Bean
45 public static PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
46 final JpaTransactionManager transactionManager = new JpaTransactionManager();
47 transactionManager.setEntityManagerFactory(emf);
48 return transactionManager;
49 }
50
51 @Bean
52 @Primary
53 public static JpaProperties properties() {
54 final JpaProperties jpaProperties = new JpaProperties();
55 jpaProperties.setShowSql(true);
56 jpaProperties.setDatabasePlatform("org.eclipse.persistence.platform.database.H2Platform");
57 return jpaProperties;
58 }
59
60 private static Map<String, ?> initJpaProperties() {
61 final Map<String, Object> ret = new HashMap<>();
62 // Add any JpaProperty you are interested in and is supported by your Database and JPA implementation
63 ret.put(PersistenceUnitProperties.BATCH_WRITING, BatchWriting.JDBC);
64 ret.put(PersistenceUnitProperties.LOGGING_LEVEL, SessionLog.FINEST_LABEL);
65 ret.put(PersistenceUnitProperties.WEAVING, "false");
66 ret.put(PersistenceUnitProperties.DDL_GENERATION, PersistenceUnitProperties.CREATE_ONLY);
67 ret.put(PersistenceUnitProperties.DDL_GENERATION_MODE, PersistenceUnitProperties.DDL_DATABASE_GENERATION);
68 return ret;
69 }
70}
Al extender JpaBaseConfiguration, debemos de implementar los métodos createJpaVendorAdapter()
y getVendorProperties()
. El primero debe de devolver una implementación de AbstractJpaVendorAdapter
, en este caso es realmente sencillo porque Spring ya dispone de una adaptador preconfigurado para EclipseLink (EclipseLinkJpaVendorAdapter
). El segundo método (getVendorProperties()) debe devolver un Map
con las propiedades JPA para la implementación JPA que elijamos. Podemos devolver un Map vacío si no queremos customizar nada.
Para completar la configuración vamos a configurar varios Beans que Spring empleará cuando sea necesario.
El primer Bean, entityManagerFactory
, se usa para construir un EntityManagerFactory
empleando el Constructor facilitado y especificando nuestros parámetros. En este caso le estamos facilitando el nombre de nuestro PersistenceUnit
, el dataSource y el nombre de los paquetes donde se encuentran las Entidades y alguna propiedad JPA más.
También definimos un Bean como transactionManager
. En este caso empleamos el gestor de transacciones facilitado por Spring, JpaTransactionManager.
Finalmente definimos un DataSource para nuestro proveedor de persistencia. En este caso empleamos el simple DriverManagerDataSource, aunque en un entorno de producción es recomendable usar un datasource que pueda ofrecer un pool de conexiones. Todos estos parámetros serán usados con prioridad respecto a los que se hayan podido definir en el fichero de propiedades de la aplicación.
Connection Pooling / Pool de conexiones a la base de datos
Si estamos empleando Spring-Boot con el servidor Apache Tomcat embebido, podemos usar el DataSource que emplea Tomcat en su contendedor, que dispone de capacidad para hacer un pool de conexiones a la base de datos.
1@Bean
2public DataSource dataSource() {
3 //In classpath from spring-boot-starter-web
4 final Properties pool = new Properties();
5 pool.put("driverClassName", "org.postgresql.Driver");
6 pool.put("url", "jdbc:postgresql://example.com:5432/DatabaseName");
7 pool.put("username", "user");
8 pool.put("password", "password");
9 pool.put("minIdle", 1);
10 return new org.apache.tomcat.jdbc.pool.DataSourceFactory().createDataSource(pool);
11}
En este caso, en lugar de devolver DriverManagerDataSource, vamos a usar el DataSourceFactory de Tomcat para generar un DataSource con los parámetros especificados. En esta página puedes encontrar un listado con todos los parámetros aceptados para poner a punto correctamente las conexiones a la base de datos.
Finalmente, al ejecutar la aplicación, Spring-Boot cogerá la configuración que hemos definido y creará un EntityManagerFactory usando EclipseLink en lugar de Hibernate.
El código fuente completo de este artículo puede encontrarse en GitHub.