diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java index ccdf9187722..e72485d266f 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java @@ -44,7 +44,6 @@ import org.springframework.beans.BeansException; import org.springframework.beans.PropertyValues; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor; @@ -296,10 +295,8 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport /** * Build a cache key for the given bean class and bean name. - *

Note: As of 4.2.3, this implementation does not return a concatenated - * class/name String anymore but rather the most efficient cache key possible: - * a plain bean name, prepended with {@link BeanFactory#FACTORY_BEAN_PREFIX} - * in case of a {@code FactoryBean}; or if no bean name specified, then the + *

Note: As of 7.0.2, this implementation returns a composed cache key + * for bean class plus bean name; or if no bean name specified, then the * given bean {@code Class} as-is. * @param beanClass the bean class * @param beanName the bean name @@ -307,8 +304,7 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport */ protected Object getCacheKey(Class beanClass, @Nullable String beanName) { if (StringUtils.hasLength(beanName)) { - return (FactoryBean.class.isAssignableFrom(beanClass) ? - BeanFactory.FACTORY_BEAN_PREFIX + beanName : beanName); + return new ComposedCacheKey(beanClass, beanName); } else { return beanClass; @@ -615,4 +611,12 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport protected abstract Object @Nullable [] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName, @Nullable TargetSource customTargetSource) throws BeansException; + + /** + * Composed cache key for bean class plus bean name. + * @see #getCacheKey(Class, String) + */ + private record ComposedCacheKey(Class beanClass, String beanName) { + } + } diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/EntityManagerPointcut.java b/spring-orm/src/test/java/org/springframework/orm/jpa/EntityManagerPointcut.java new file mode 100644 index 00000000000..5ef28f5f3ea --- /dev/null +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/EntityManagerPointcut.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jpa; + +import java.io.Serializable; + +import jakarta.persistence.EntityManager; + +import org.springframework.aop.ClassFilter; +import org.springframework.aop.MethodMatcher; +import org.springframework.aop.Pointcut; + +/** + * @author Juergen Hoeller + */ +public class EntityManagerPointcut implements Pointcut, Serializable { + + @Override + public ClassFilter getClassFilter() { + return (EntityManager.class::isAssignableFrom); + } + + @Override + public MethodMatcher getMethodMatcher() { + return MethodMatcher.TRUE; + } + +} diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/HibernateEntityManagerFactoryIntegrationTests.java b/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/HibernateEntityManagerFactoryIntegrationTests.java index 00062c3787a..0f7a8fba6cd 100644 --- a/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/HibernateEntityManagerFactoryIntegrationTests.java +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/HibernateEntityManagerFactoryIntegrationTests.java @@ -23,6 +23,7 @@ import org.hibernate.SessionFactory; import org.junit.jupiter.api.Test; import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.support.AopUtils; import org.springframework.aop.target.SingletonTargetSource; import org.springframework.orm.jpa.AbstractContainerEntityManagerFactoryIntegrationTests; import org.springframework.orm.jpa.EntityManagerFactoryInfo; @@ -45,6 +46,11 @@ class HibernateEntityManagerFactoryIntegrationTests extends AbstractContainerEnt } + @Test + void testAdvisedEntityManagerProxyFromSmartFactoryBean() { + assertThat(AopUtils.isAopProxy(sharedEntityManager)).isTrue(); + } + @Test void testCanCastNativeEntityManagerFactoryToHibernateEntityManagerFactoryImpl() { EntityManagerFactoryInfo emfi = (EntityManagerFactoryInfo) entityManagerFactory; diff --git a/spring-orm/src/test/resources/org/springframework/orm/jpa/hibernate/hibernate-manager.xml b/spring-orm/src/test/resources/org/springframework/orm/jpa/hibernate/hibernate-manager.xml index 11a3e60512c..c88d20545d7 100644 --- a/spring-orm/src/test/resources/org/springframework/orm/jpa/hibernate/hibernate-manager.xml +++ b/spring-orm/src/test/resources/org/springframework/orm/jpa/hibernate/hibernate-manager.xml @@ -32,4 +32,9 @@ + + + + +