From 309e70a48e6c8ce5e3199d31a753f08d82f60020 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 12 Oct 2018 22:53:50 +0200 Subject: [PATCH] Separate factory method cache for introspection purposes Issue: SPR-17358 Issue: SPR-8891 --- .../support/AbstractAutowireCapableBeanFactory.java | 1 + .../beans/factory/support/ConstructorResolver.java | 6 +++--- .../factory/support/DefaultListableBeanFactory.java | 10 ++-------- .../beans/factory/support/RootBeanDefinition.java | 9 +++++---- .../configuration/BeanMethodQualificationTests.java | 4 ++-- 5 files changed, 13 insertions(+), 17 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java index f827fbf7fd04..13bb3cf44e30 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java @@ -775,6 +775,7 @@ protected Class getTypeForFactoryMethod(String beanName, RootBeanDefinition m } } + mbd.factoryMethodToIntrospect = uniqueCandidate; if (commonType == null) { return null; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java index a328d6541122..b4cfb1bdcb71 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java @@ -337,9 +337,7 @@ else if (!Arrays.equals(uniqueCandidate.getParameterTypes(), candidate.getParame } } } - synchronized (mbd.constructorArgumentLock) { - mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate; - } + mbd.factoryMethodToIntrospect = uniqueCandidate; } /** @@ -448,6 +446,7 @@ public BeanWrapper instantiateUsingFactoryMethod( if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) { Method uniqueCandidate = candidateList.get(0); if (uniqueCandidate.getParameterCount() == 0) { + mbd.factoryMethodToIntrospect = uniqueCandidate; synchronized (mbd.constructorArgumentLock) { mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate; mbd.constructorArgumentsResolved = true; @@ -598,6 +597,7 @@ else if (ambiguousFactoryMethods != null) { } if (explicitArgs == null && argsHolderToUse != null) { + mbd.factoryMethodToIntrospect = factoryMethodToUse; argsHolderToUse.storeCache(mbd, factoryMethodToUse); } } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java index 7ed5704bd162..9e702c2e01e2 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java @@ -755,14 +755,8 @@ protected boolean isAutowireCandidate(String beanName, RootBeanDefinition mbd, String beanDefinitionName = BeanFactoryUtils.transformedBeanName(beanName); resolveBeanClass(mbd, beanDefinitionName); - if (mbd.isFactoryMethodUnique) { - boolean resolve; - synchronized (mbd.constructorArgumentLock) { - resolve = (mbd.resolvedConstructorOrFactoryMethod == null); - } - if (resolve) { - new ConstructorResolver(this).resolveFactoryMethodIfPossible(mbd); - } + if (mbd.isFactoryMethodUnique && mbd.factoryMethodToIntrospect == null) { + new ConstructorResolver(this).resolveFactoryMethodIfPossible(mbd); } return resolver.isAutowireCandidate( new BeanDefinitionHolder(mbd, beanName, getAliases(beanDefinitionName)), descriptor); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java index c8de0f5bee85..f28dc09bdeca 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java @@ -75,6 +75,10 @@ public class RootBeanDefinition extends AbstractBeanDefinition { @Nullable volatile ResolvableType factoryMethodReturnType; + /** Package-visible field for caching a unique factory method candidate for introspection. */ + @Nullable + volatile Method factoryMethodToIntrospect; + /** Common lock for the four constructor fields below. */ final Object constructorArgumentLock = new Object(); @@ -370,10 +374,7 @@ public boolean isFactoryMethod(Method candidate) { */ @Nullable public Method getResolvedFactoryMethod() { - synchronized (this.constructorArgumentLock) { - Executable candidate = this.resolvedConstructorOrFactoryMethod; - return (candidate instanceof Method ? (Method) candidate : null); - } + return this.factoryMethodToIntrospect; } public void registerExternallyManagedConfigMember(Member configMember) { diff --git a/spring-context/src/test/java/org/springframework/context/annotation/configuration/BeanMethodQualificationTests.java b/spring-context/src/test/java/org/springframework/context/annotation/configuration/BeanMethodQualificationTests.java index 89893be10591..f4acc82da763 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/configuration/BeanMethodQualificationTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/configuration/BeanMethodQualificationTests.java @@ -83,8 +83,8 @@ public void testCustomWithLazyResolution() { new AnnotationConfigApplicationContext(CustomConfig.class, CustomPojo.class); assertFalse(ctx.getBeanFactory().containsSingleton("testBean1")); assertFalse(ctx.getBeanFactory().containsSingleton("testBean2")); - // TODO: assertTrue(BeanFactoryAnnotationUtils.isQualifierMatch(value -> value.equals("boring"), - // "testBean2", ctx.getDefaultListableBeanFactory())); + assertTrue(BeanFactoryAnnotationUtils.isQualifierMatch(value -> value.equals("boring"), + "testBean2", ctx.getDefaultListableBeanFactory())); CustomPojo pojo = ctx.getBean(CustomPojo.class); assertThat(pojo.testBean.getName(), equalTo("interesting")); TestBean testBean2 = BeanFactoryAnnotationUtils.qualifiedBeanOfType(