提交 aeacf927 编写于 作者: J Juergen Hoeller

JpaTransactionManager etc can find EntityManagerFactory by...

JpaTransactionManager etc can find EntityManagerFactory by "persistenceUnitName" property now, falling back to retrieval of a unique EntityManagerFactory bean by type (analogous to @PersistenceUnit / @PersistenceContext)
上级 676ab5f0
/*
* 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.
......
/*
* 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();
......
/*
* 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;
private String entityManagerFactoryBeanName = DEFAULT_PERSISTENCE_MANAGER_FACTORY_BEAN_NAME;
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);
}
}
/**
......
/*
* 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) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册