From c986a1efc12a8c0c1c0e797ea5c0d3023e0b0287 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 1 Mar 2013 16:43:24 +0100 Subject: [PATCH] Cache target type per bean definition and allow for specifying it in advance Issue: SPR-10335 --- .../AbstractAutowireCapableBeanFactory.java | 23 ++++++++------ .../factory/support/RootBeanDefinition.java | 31 +++++++++++++++---- 2 files changed, 39 insertions(+), 15 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 3b4dfcd83d..09faf0c3b2 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 @@ -572,17 +572,22 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac } @Override - protected Class predictBeanType(String beanName, RootBeanDefinition mbd, Class... typesToMatch) { - Class beanClass = (mbd.getFactoryMethodName() != null ? - getTypeForFactoryMethod(beanName, mbd, typesToMatch) : - resolveBeanClass(mbd, beanName, typesToMatch)); + protected Class predictBeanType(String beanName, RootBeanDefinition mbd, Class... typesToMatch) { + Class targetType = mbd.getTargetType(); + if (targetType == null) { + targetType = (mbd.getFactoryMethodName() != null ? getTypeForFactoryMethod(beanName, mbd, typesToMatch) : + resolveBeanClass(mbd, beanName, typesToMatch)); + if (ObjectUtils.isEmpty(typesToMatch) || getTempClassLoader() == null) { + mbd.setTargetType(targetType); + } + } // Apply SmartInstantiationAwareBeanPostProcessors to predict the // eventual type after a before-instantiation shortcut. - if (beanClass != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { + if (targetType != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof SmartInstantiationAwareBeanPostProcessor) { SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; - Class predicted = ibp.predictBeanType(beanClass, beanName); + Class predicted = ibp.predictBeanType(targetType, beanName); if (predicted != null && (typesToMatch.length != 1 || !FactoryBean.class.equals(typesToMatch[0]) || FactoryBean.class.isAssignableFrom(predicted))) { return predicted; @@ -590,7 +595,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac } } } - return beanClass; + return targetType; } /** @@ -607,8 +612,8 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac * @return the type for the bean if determinable, or {@code null} else * @see #createBean */ - protected Class getTypeForFactoryMethod(String beanName, RootBeanDefinition mbd, Class[] typesToMatch) { - Class factoryClass; + protected Class getTypeForFactoryMethod(String beanName, RootBeanDefinition mbd, Class[] typesToMatch) { + Class factoryClass; boolean isStatic = true; String factoryBeanName = mbd.getFactoryBeanName(); 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 7eaba17a54..64d0555d49 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -61,8 +61,12 @@ public class RootBeanDefinition extends AbstractBeanDefinition { boolean allowCaching = true; + private volatile Class targetType; + boolean isFactoryMethodUnique = false; + final Object constructorArgumentLock = new Object(); + /** Package-visible field for caching the resolved constructor or factory method */ Object resolvedConstructorOrFactoryMethod; @@ -75,15 +79,13 @@ public class RootBeanDefinition extends AbstractBeanDefinition { /** Package-visible field for caching partly prepared constructor arguments */ Object[] preparedConstructorArguments; - final Object constructorArgumentLock = new Object(); - - /** Package-visible field that indicates a before-instantiation post-processor having kicked in */ - volatile Boolean beforeInstantiationResolved; + final Object postProcessingLock = new Object(); /** Package-visible field that indicates MergedBeanDefinitionPostProcessor having been applied */ boolean postProcessed = false; - final Object postProcessingLock = new Object(); + /** Package-visible field that indicates a before-instantiation post-processor having kicked in */ + volatile Boolean beforeInstantiationResolved; /** @@ -236,6 +238,8 @@ public class RootBeanDefinition extends AbstractBeanDefinition { if (original instanceof RootBeanDefinition) { RootBeanDefinition originalRbd = (RootBeanDefinition) original; this.decoratedDefinition = originalRbd.decoratedDefinition; + this.allowCaching = originalRbd.allowCaching; + this.targetType = originalRbd.targetType; this.isFactoryMethodUnique = originalRbd.isFactoryMethodUnique; } } @@ -251,6 +255,21 @@ public class RootBeanDefinition extends AbstractBeanDefinition { } } + /** + * Specify the target type of this bean definition, if known in advance. + */ + public void setTargetType(Class targetType) { + this.targetType = targetType; + } + + /** + * Return the target type of this bean definition, if known + * (either specified in advance or resolved on first instantiation). + */ + public Class getTargetType() { + return this.targetType; + } + /** * Specify a factory method name that refers to a non-overloaded method. */