JpaTransactionManager etc can find EntityManagerFactory by "persistenceUnitName" property now, falling back to retrieval of a unique EntityManagerFactory bean by type (analogous to @PersistenceUnit / @PersistenceContext)
This commit is contained in:
parent
676ab5f0b1
commit
aeacf9278f
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -19,13 +19,16 @@ package org.springframework.orm.jpa;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
|
|
@ -40,13 +43,15 @@ import org.springframework.util.CollectionUtils;
|
|||
* @see JpaAccessor
|
||||
* @see EntityManagerFactoryUtils
|
||||
*/
|
||||
public abstract class EntityManagerFactoryAccessor {
|
||||
public abstract class EntityManagerFactoryAccessor implements BeanFactoryAware {
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private EntityManagerFactory entityManagerFactory;
|
||||
|
||||
private String persistenceUnitName;
|
||||
|
||||
private final Map<String, Object> jpaPropertyMap = new HashMap<String, Object>();
|
||||
|
||||
|
||||
|
|
@ -68,6 +73,25 @@ public abstract class EntityManagerFactoryAccessor {
|
|||
return this.entityManagerFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the persistence unit to access the EntityManagerFactory for.
|
||||
* <p>This is an alternative to specifying the EntityManagerFactory by direct reference,
|
||||
* resolving it by its persistence unit name instead. If no EntityManagerFactory and
|
||||
* no persistence unit name have been specified, a default EntityManagerFactory will
|
||||
* be retrieved through finding a single unique bean of type EntityManagerFactory.
|
||||
* @see #setEntityManagerFactory
|
||||
*/
|
||||
public void setPersistenceUnitName(String persistenceUnitName) {
|
||||
this.persistenceUnitName = persistenceUnitName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the persistence unit to access the EntityManagerFactory for, if any.
|
||||
*/
|
||||
public String getPersistenceUnitName() {
|
||||
return this.persistenceUnitName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify JPA properties, to be passed into
|
||||
* <code>EntityManagerFactory.createEntityManager(Map)</code> (if any).
|
||||
|
|
@ -100,6 +124,22 @@ public abstract class EntityManagerFactoryAccessor {
|
|||
return this.jpaPropertyMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an EntityManagerFactory by persistence unit name, if none set explicitly.
|
||||
* Falls back to a default EntityManagerFactory bean if no persistence unit specified.
|
||||
* @see #setPersistenceUnitName
|
||||
*/
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
if (getEntityManagerFactory() == null) {
|
||||
if (!(beanFactory instanceof ListableBeanFactory)) {
|
||||
throw new IllegalStateException("Cannot retrieve EntityManagerFactory by persistence unit name " +
|
||||
"in a non-listable BeanFactory: " + beanFactory);
|
||||
}
|
||||
ListableBeanFactory lbf = (ListableBeanFactory) beanFactory;
|
||||
setEntityManagerFactory(EntityManagerFactoryUtils.findEntityManagerFactory(lbf, getPersistenceUnitName()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain a new EntityManager from this accessor's EntityManagerFactory.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -46,6 +46,7 @@ import org.springframework.transaction.support.ResourceHolderSynchronization;
|
|||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Helper class featuring methods for JPA EntityManager handling,
|
||||
|
|
@ -80,7 +81,8 @@ public abstract class EntityManagerFactoryUtils {
|
|||
* the persistence unit name will be matched against the Spring bean name,
|
||||
* assuming that the EntityManagerFactory bean names follow that convention.
|
||||
* @param beanFactory the ListableBeanFactory to search
|
||||
* @param unitName the name of the persistence unit (never empty)
|
||||
* @param unitName the name of the persistence unit (may be <code>null</code> or empty,
|
||||
* in which case a single bean of type EntityManagerFactory will be searched for)
|
||||
* @return the EntityManagerFactory
|
||||
* @throws NoSuchBeanDefinitionException if there is no such EntityManagerFactory in the context
|
||||
* @see EntityManagerFactoryInfo#getPersistenceUnitName()
|
||||
|
|
@ -89,22 +91,25 @@ public abstract class EntityManagerFactoryUtils {
|
|||
ListableBeanFactory beanFactory, String unitName) throws NoSuchBeanDefinitionException {
|
||||
|
||||
Assert.notNull(beanFactory, "ListableBeanFactory must not be null");
|
||||
Assert.hasLength(unitName, "Unit name must not be empty");
|
||||
|
||||
// See whether we can find an EntityManagerFactory with matching persistence unit name.
|
||||
String[] candidateNames =
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, EntityManagerFactory.class);
|
||||
for (String candidateName : candidateNames) {
|
||||
EntityManagerFactory emf = (EntityManagerFactory) beanFactory.getBean(candidateName);
|
||||
if (emf instanceof EntityManagerFactoryInfo) {
|
||||
if (unitName.equals(((EntityManagerFactoryInfo) emf).getPersistenceUnitName())) {
|
||||
return emf;
|
||||
if (StringUtils.hasLength(unitName)) {
|
||||
// See whether we can find an EntityManagerFactory with matching persistence unit name.
|
||||
String[] candidateNames =
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, EntityManagerFactory.class);
|
||||
for (String candidateName : candidateNames) {
|
||||
EntityManagerFactory emf = (EntityManagerFactory) beanFactory.getBean(candidateName);
|
||||
if (emf instanceof EntityManagerFactoryInfo) {
|
||||
if (unitName.equals(((EntityManagerFactoryInfo) emf).getPersistenceUnitName())) {
|
||||
return emf;
|
||||
}
|
||||
}
|
||||
}
|
||||
// No matching persistence unit found - simply take the EntityManagerFactory
|
||||
// with the persistence unit name as bean name (by convention).
|
||||
return beanFactory.getBean(unitName, EntityManagerFactory.class);
|
||||
}
|
||||
else {
|
||||
return BeanFactoryUtils.beanOfType(beanFactory, EntityManagerFactory.class);
|
||||
}
|
||||
// No matching persistence unit found - simply take the EntityManagerFactory
|
||||
// with the persistence unit name as bean name (by convention).
|
||||
return beanFactory.getBean(unitName, EntityManagerFactory.class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -26,7 +26,11 @@ import javax.persistence.PersistenceException;
|
|||
import javax.persistence.RollbackException;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.DataAccessUtils;
|
||||
import org.springframework.jdbc.datasource.ConnectionHandle;
|
||||
|
|
@ -105,10 +109,12 @@ import org.springframework.util.CollectionUtils;
|
|||
* @see org.springframework.transaction.jta.JtaTransactionManager
|
||||
*/
|
||||
public class JpaTransactionManager extends AbstractPlatformTransactionManager
|
||||
implements ResourceTransactionManager, InitializingBean {
|
||||
implements ResourceTransactionManager, BeanFactoryAware, InitializingBean {
|
||||
|
||||
private EntityManagerFactory entityManagerFactory;
|
||||
|
||||
private String persistenceUnitName;
|
||||
|
||||
private final Map<String, Object> jpaPropertyMap = new HashMap<String, Object>();
|
||||
|
||||
private DataSource dataSource;
|
||||
|
|
@ -138,6 +144,10 @@ public class JpaTransactionManager extends AbstractPlatformTransactionManager
|
|||
|
||||
/**
|
||||
* Set the EntityManagerFactory that this instance should manage transactions for.
|
||||
* <p>Alternatively, specify the persistence unit name of the target EntityManagerFactory.
|
||||
* By default, a default EntityManagerFactory will be retrieved through finding a
|
||||
* single unique bean of type EntityManagerFactory in the containing BeanFactory.
|
||||
* @see #setPersistenceUnitName
|
||||
*/
|
||||
public void setEntityManagerFactory(EntityManagerFactory emf) {
|
||||
this.entityManagerFactory = emf;
|
||||
|
|
@ -150,6 +160,25 @@ public class JpaTransactionManager extends AbstractPlatformTransactionManager
|
|||
return this.entityManagerFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the persistence unit to manage transactions for.
|
||||
* <p>This is an alternative to specifying the EntityManagerFactory by direct reference,
|
||||
* resolving it by its persistence unit name instead. If no EntityManagerFactory and
|
||||
* no persistence unit name have been specified, a default EntityManagerFactory will
|
||||
* be retrieved through finding a single unique bean of type EntityManagerFactory.
|
||||
* @see #setEntityManagerFactory
|
||||
*/
|
||||
public void setPersistenceUnitName(String persistenceUnitName) {
|
||||
this.persistenceUnitName = persistenceUnitName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the persistence unit to manage transactions for, if any.
|
||||
*/
|
||||
public String getPersistenceUnitName() {
|
||||
return this.persistenceUnitName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify JPA properties, to be passed into
|
||||
* <code>EntityManagerFactory.createEntityManager(Map)</code> (if any).
|
||||
|
|
@ -247,6 +276,22 @@ public class JpaTransactionManager extends AbstractPlatformTransactionManager
|
|||
return this.jpaDialect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an EntityManagerFactory by persistence unit name, if none set explicitly.
|
||||
* Falls back to a default EntityManagerFactory bean if no persistence unit specified.
|
||||
* @see #setPersistenceUnitName
|
||||
*/
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
if (getEntityManagerFactory() == null) {
|
||||
if (!(beanFactory instanceof ListableBeanFactory)) {
|
||||
throw new IllegalStateException("Cannot retrieve EntityManagerFactory by persistence unit name " +
|
||||
"in a non-listable BeanFactory: " + beanFactory);
|
||||
}
|
||||
ListableBeanFactory lbf = (ListableBeanFactory) beanFactory;
|
||||
setEntityManagerFactory(EntityManagerFactoryUtils.findEntityManagerFactory(lbf, getPersistenceUnitName()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly initialize the JPA dialect, creating a default one
|
||||
* for the specified EntityManagerFactory if none set.
|
||||
|
|
@ -254,7 +299,7 @@ public class JpaTransactionManager extends AbstractPlatformTransactionManager
|
|||
*/
|
||||
public void afterPropertiesSet() {
|
||||
if (getEntityManagerFactory() == null) {
|
||||
throw new IllegalArgumentException("Property 'entityManagerFactory' is required");
|
||||
throw new IllegalArgumentException("'entityManagerFactory' or 'persistenceUnitName' is required");
|
||||
}
|
||||
if (getEntityManagerFactory() instanceof EntityManagerFactoryInfo) {
|
||||
EntityManagerFactoryInfo emfInfo = (EntityManagerFactoryInfo) getEntityManagerFactory();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -17,7 +17,6 @@
|
|||
package org.springframework.orm.jpa.support;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
|
@ -27,9 +26,10 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.orm.jpa.EntityManagerHolder;
|
||||
import org.springframework.orm.jpa.EntityManagerFactoryUtils;
|
||||
import org.springframework.orm.jpa.EntityManagerHolder;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
|
@ -47,10 +47,10 @@ import org.springframework.web.filter.OncePerRequestFilter;
|
|||
* as for non-transactional read-only execution.
|
||||
*
|
||||
* <p>Looks up the EntityManagerFactory in Spring's root web application context.
|
||||
* Supports a "entityManagerFactoryBeanName" filter init-param in <code>web.xml</code>;
|
||||
* the default bean name is "entityManagerFactory". Looks up the EntityManagerFactory
|
||||
* on each request, to avoid initialization order issues (when using ContextLoaderServlet,
|
||||
* the root application context will get initialized <i>after</i> this filter).
|
||||
* Supports an "entityManagerFactoryBeanName" filter init-param in <code>web.xml</code>;
|
||||
* the default bean name is "entityManagerFactory". As an alternative, the
|
||||
* "persistenceUnitName" init-param allows for retrieval by logical unit name
|
||||
* (as specified in <code>persistence.xml</code>).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
|
|
@ -63,15 +63,28 @@ import org.springframework.web.filter.OncePerRequestFilter;
|
|||
*/
|
||||
public class OpenEntityManagerInViewFilter extends OncePerRequestFilter {
|
||||
|
||||
public static final String DEFAULT_PERSISTENCE_MANAGER_FACTORY_BEAN_NAME = "entityManagerFactory";
|
||||
/**
|
||||
* Default EntityManagerFactory bean name: "entityManagerFactory".
|
||||
* Only applies when no "persistenceUnitName" param has been specified.
|
||||
* @see #setEntityManagerFactoryBeanName
|
||||
* @see #setPersistenceUnitName
|
||||
*/
|
||||
public static final String DEFAULT_ENTITY_MANAGER_FACTORY_BEAN_NAME = "entityManagerFactory";
|
||||
|
||||
private String entityManagerFactoryBeanName = DEFAULT_PERSISTENCE_MANAGER_FACTORY_BEAN_NAME;
|
||||
private String entityManagerFactoryBeanName;
|
||||
|
||||
private String persistenceUnitName;
|
||||
|
||||
private volatile EntityManagerFactory entityManagerFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Set the bean name of the EntityManagerFactory to fetch from Spring's
|
||||
* root application context. Default is "entityManagerFactory".
|
||||
* @see #DEFAULT_PERSISTENCE_MANAGER_FACTORY_BEAN_NAME
|
||||
* root application context.
|
||||
* <p>Default is "entityManagerFactory". Note that this default only applies
|
||||
* when no "persistenceUnitName" param has been specified.
|
||||
* @see #setPersistenceUnitName
|
||||
* @see #DEFAULT_ENTITY_MANAGER_FACTORY_BEAN_NAME
|
||||
*/
|
||||
public void setEntityManagerFactoryBeanName(String entityManagerFactoryBeanName) {
|
||||
this.entityManagerFactoryBeanName = entityManagerFactoryBeanName;
|
||||
|
|
@ -85,6 +98,27 @@ public class OpenEntityManagerInViewFilter extends OncePerRequestFilter {
|
|||
return this.entityManagerFactoryBeanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the persistence unit to access the EntityManagerFactory for.
|
||||
* <p>This is an alternative to specifying the EntityManagerFactory by bean name,
|
||||
* resolving it by its persistence unit name instead. If no bean name and no persistence
|
||||
* unit name have been specified, we'll check whether a bean exists for the default
|
||||
* bean name "entityManagerFactory"; if not, a default EntityManagerFactory will
|
||||
* be retrieved through finding a single unique bean of type EntityManagerFactory.
|
||||
* @see #setEntityManagerFactoryBeanName
|
||||
* @see #DEFAULT_ENTITY_MANAGER_FACTORY_BEAN_NAME
|
||||
*/
|
||||
public void setPersistenceUnitName(String persistenceUnitName) {
|
||||
this.persistenceUnitName = persistenceUnitName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the persistence unit to access the EntityManagerFactory for, if any.
|
||||
*/
|
||||
protected String getPersistenceUnitName() {
|
||||
return this.persistenceUnitName;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(
|
||||
|
|
@ -126,29 +160,39 @@ public class OpenEntityManagerInViewFilter extends OncePerRequestFilter {
|
|||
/**
|
||||
* Look up the EntityManagerFactory that this filter should use,
|
||||
* taking the current HTTP request as argument.
|
||||
* <p>Default implementation delegates to the <code>lookupEntityManagerFactory</code>
|
||||
* without arguments.
|
||||
* <p>The default implementation delegates to the <code>lookupEntityManagerFactory</code>
|
||||
* without arguments, caching the EntityManagerFactory reference once obtained.
|
||||
* @return the EntityManagerFactory to use
|
||||
* @see #lookupEntityManagerFactory()
|
||||
*/
|
||||
protected EntityManagerFactory lookupEntityManagerFactory(HttpServletRequest request) {
|
||||
return lookupEntityManagerFactory();
|
||||
if (this.entityManagerFactory == null) {
|
||||
this.entityManagerFactory = lookupEntityManagerFactory();
|
||||
}
|
||||
return this.entityManagerFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the EntityManagerFactory that this filter should use.
|
||||
* The default implementation looks for a bean with the specified name
|
||||
* <p>The default implementation looks for a bean with the specified name
|
||||
* in Spring's root application context.
|
||||
* @return the EntityManagerFactory to use
|
||||
* @see #getEntityManagerFactoryBeanName
|
||||
*/
|
||||
protected EntityManagerFactory lookupEntityManagerFactory() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using EntityManagerFactory '" + getEntityManagerFactoryBeanName() +
|
||||
"' for OpenEntityManagerInViewFilter");
|
||||
}
|
||||
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
|
||||
return wac.getBean(getEntityManagerFactoryBeanName(), EntityManagerFactory.class);
|
||||
String emfBeanName = getEntityManagerFactoryBeanName();
|
||||
String puName = getPersistenceUnitName();
|
||||
if (StringUtils.hasLength(emfBeanName)) {
|
||||
return wac.getBean(emfBeanName, EntityManagerFactory.class);
|
||||
}
|
||||
else if (!StringUtils.hasLength(puName) && wac.containsBean(DEFAULT_ENTITY_MANAGER_FACTORY_BEAN_NAME)) {
|
||||
return wac.getBean(DEFAULT_ENTITY_MANAGER_FACTORY_BEAN_NAME, EntityManagerFactory.class);
|
||||
}
|
||||
else {
|
||||
// Includes fallback search for single EntityManagerFactory bean by type.
|
||||
return EntityManagerFactoryUtils.findEntityManagerFactory(wac, puName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -67,7 +67,7 @@ public class SharedEntityManagerBean extends EntityManagerFactoryAccessor
|
|||
* @see javax.persistence.EntityManager
|
||||
*/
|
||||
public void setEntityManagerInterface(Class<? extends EntityManager> entityManagerInterface) {
|
||||
Assert.notNull(entityManagerInterface, "entityManagerInterface must not be null");
|
||||
Assert.notNull(entityManagerInterface, "'entityManagerInterface' must not be null");
|
||||
Assert.isAssignable(EntityManager.class, entityManagerInterface);
|
||||
this.entityManagerInterface = entityManagerInterface;
|
||||
}
|
||||
|
|
@ -76,7 +76,7 @@ public class SharedEntityManagerBean extends EntityManagerFactoryAccessor
|
|||
public final void afterPropertiesSet() {
|
||||
EntityManagerFactory emf = getEntityManagerFactory();
|
||||
if (emf == null) {
|
||||
throw new IllegalArgumentException("entityManagerFactory is required");
|
||||
throw new IllegalArgumentException("'entityManagerFactory' or 'persistenceUnitName' is required");
|
||||
}
|
||||
Class[] ifcs = null;
|
||||
if (emf instanceof EntityManagerFactoryInfo) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue