SharedEntityManagerCreator's EntityManager proxies are fully serializable now (SPR-6684)

This commit is contained in:
Juergen Hoeller
2010-02-01 14:48:18 +00:00
parent df54c8613d
commit db71811c5a
5 changed files with 125 additions and 43 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2010 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.
@@ -16,6 +16,9 @@
package org.springframework.orm.jpa;
import java.io.NotSerializableException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -37,6 +40,9 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
@@ -73,8 +79,8 @@ import org.springframework.util.CollectionUtils;
* @see LocalContainerEntityManagerFactoryBean
*/
public abstract class AbstractEntityManagerFactoryBean implements
FactoryBean<EntityManagerFactory>, BeanClassLoaderAware, InitializingBean, DisposableBean,
EntityManagerFactoryInfo, PersistenceExceptionTranslator {
FactoryBean<EntityManagerFactory>, BeanClassLoaderAware, BeanFactoryAware, BeanNameAware,
InitializingBean, DisposableBean, EntityManagerFactoryInfo, PersistenceExceptionTranslator, Serializable {
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
@@ -95,9 +101,15 @@ public abstract class AbstractEntityManagerFactoryBean implements
private ClassLoader beanClassLoader = getClass().getClassLoader();
private BeanFactory beanFactory;
private String beanName;
/** Raw EntityManagerFactory as returned by the PersistenceProvider */
public EntityManagerFactory nativeEntityManagerFactory;
private EntityManagerFactoryPlusOperations plusOperations;
private EntityManagerFactory entityManagerFactory;
@@ -254,6 +266,14 @@ public abstract class AbstractEntityManagerFactoryBean implements
return this.beanClassLoader;
}
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public void setBeanName(String name) {
this.beanName = name;
}
public final void afterPropertiesSet() throws PersistenceException {
if (this.jpaVendorAdapter != null) {
@@ -317,14 +337,13 @@ public abstract class AbstractEntityManagerFactoryBean implements
ifcs.addAll(ClassUtils.getAllInterfacesForClassAsSet(emf.getClass(), this.beanClassLoader));
}
ifcs.add(EntityManagerFactoryInfo.class);
EntityManagerFactoryPlusOperations plusOperations = null;
if (getJpaDialect() != null && getJpaDialect().supportsEntityManagerFactoryPlusOperations()) {
plusOperations = getJpaDialect().getEntityManagerFactoryPlusOperations(emf);
this.plusOperations = getJpaDialect().getEntityManagerFactoryPlusOperations(emf);
ifcs.add(EntityManagerFactoryPlusOperations.class);
}
return (EntityManagerFactory) Proxy.newProxyInstance(
this.beanClassLoader, ifcs.toArray(new Class[ifcs.size()]),
new ManagedEntityManagerFactoryInvocationHandler(emf, this, plusOperations));
new ManagedEntityManagerFactoryInvocationHandler(this));
}
/**
@@ -390,25 +409,67 @@ public abstract class AbstractEntityManagerFactoryBean implements
}
//---------------------------------------------------------------------
// Serialization support
//---------------------------------------------------------------------
Object invokeProxyMethod(Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass().isAssignableFrom(EntityManagerFactoryInfo.class)) {
return method.invoke(this, args);
}
else if (method.getDeclaringClass().equals(EntityManagerFactoryPlusOperations.class)) {
return method.invoke(this.plusOperations, args);
}
Object retVal = method.invoke(this.nativeEntityManagerFactory, args);
if (retVal instanceof EntityManager) {
EntityManager rawEntityManager = (EntityManager) retVal;
retVal = ExtendedEntityManagerCreator.createApplicationManagedEntityManager(rawEntityManager, this);
}
return retVal;
}
protected Object writeReplace() throws ObjectStreamException {
if (this.beanFactory != null && this.beanName != null) {
return new SerializedEntityManagerFactoryBeanReference(this.beanFactory, this.beanName);
}
else {
throw new NotSerializableException("EntityManagerFactoryBean does not run within a BeanFactory");
}
}
/**
* Minimal bean reference to the surrounding AbstractEntityManagerFactoryBean.
* Resolved to the actual AbstractEntityManagerFactoryBean instance on deserialization.
*/
private static class SerializedEntityManagerFactoryBeanReference implements Serializable {
private final BeanFactory beanFactory;
private final String lookupName;
public SerializedEntityManagerFactoryBeanReference(BeanFactory beanFactory, String beanName) {
this.beanFactory = beanFactory;
this.lookupName = BeanFactory.FACTORY_BEAN_PREFIX + beanName;
}
private Object readResolve() {
return this.beanFactory.getBean(this.lookupName, AbstractEntityManagerFactoryBean.class);
}
}
/**
* Dynamic proxy invocation handler proxying an EntityManagerFactory to
* return a proxy EntityManager if necessary from createEntityManager()
* methods.
*/
private static class ManagedEntityManagerFactoryInvocationHandler implements InvocationHandler {
private static class ManagedEntityManagerFactoryInvocationHandler implements InvocationHandler, Serializable {
private final EntityManagerFactory targetEntityManagerFactory;
private final AbstractEntityManagerFactoryBean entityManagerFactoryBean;
private final EntityManagerFactoryInfo entityManagerFactoryInfo;
private final EntityManagerFactoryPlusOperations entityManagerFactoryPlusOperations;
public ManagedEntityManagerFactoryInvocationHandler(EntityManagerFactory targetEmf,
EntityManagerFactoryInfo emfInfo, EntityManagerFactoryPlusOperations entityManagerFactoryPlusOperations) {
this.targetEntityManagerFactory = targetEmf;
this.entityManagerFactoryInfo = emfInfo;
this.entityManagerFactoryPlusOperations = entityManagerFactoryPlusOperations;
public ManagedEntityManagerFactoryInvocationHandler(AbstractEntityManagerFactoryBean emfb) {
this.entityManagerFactoryBean = emfb;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
@@ -421,20 +482,7 @@ public abstract class AbstractEntityManagerFactoryBean implements
// Use hashCode of EntityManagerFactory proxy.
return System.identityHashCode(proxy);
}
else if (method.getDeclaringClass().isAssignableFrom(EntityManagerFactoryInfo.class)) {
return method.invoke(this.entityManagerFactoryInfo, args);
}
else if (method.getDeclaringClass().equals(EntityManagerFactoryPlusOperations.class)) {
return method.invoke(this.entityManagerFactoryPlusOperations, args);
}
Object retVal = method.invoke(this.targetEntityManagerFactory, args);
if (retVal instanceof EntityManager) {
EntityManager rawEntityManager = (EntityManager) retVal;
retVal = ExtendedEntityManagerCreator.createApplicationManagedEntityManager(
rawEntityManager, this.entityManagerFactoryInfo);
}
return retVal;
return this.entityManagerFactoryBean.invokeProxyMethod(method, args);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();

View File

@@ -16,6 +16,9 @@
package org.springframework.orm.jpa;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -123,7 +126,7 @@ public abstract class SharedEntityManagerCreator {
* transactional EntityManager, if any; else, it will fall back
* to a newly created EntityManager per operation.
*/
private static class SharedEntityManagerInvocationHandler implements InvocationHandler {
private static class SharedEntityManagerInvocationHandler implements InvocationHandler, Serializable {
private final Log logger = LogFactory.getLog(getClass());
@@ -131,11 +134,15 @@ public abstract class SharedEntityManagerCreator {
private final Map properties;
private final ClassLoader proxyClassLoader;
private transient volatile ClassLoader proxyClassLoader;
public SharedEntityManagerInvocationHandler(EntityManagerFactory target, Map properties) {
this.targetFactory = target;
this.properties = properties;
initProxyClassLoader();
}
private void initProxyClassLoader() {
if (this.targetFactory instanceof EntityManagerFactoryInfo) {
this.proxyClassLoader = ((EntityManagerFactoryInfo) this.targetFactory).getBeanClassLoader();
}
@@ -254,6 +261,13 @@ public abstract class SharedEntityManagerCreator {
}
}
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// Rely on default serialization, just initialize state after deserialization.
ois.defaultReadObject();
// Initialize transient fields.
initProxyClassLoader();
}
}