Bean class name may contain SpEL expression for late resolution
Issue: SPR-12817
This commit is contained in:
parent
66ec5ea2d1
commit
768f6e836a
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
|
|
@ -443,37 +443,43 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
|||
* @see #doCreateBean
|
||||
*/
|
||||
@Override
|
||||
protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
|
||||
throws BeanCreationException {
|
||||
|
||||
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Creating instance of bean '" + beanName + "'");
|
||||
}
|
||||
// Make sure bean class is actually resolved at this point.
|
||||
resolveBeanClass(mbd, beanName);
|
||||
RootBeanDefinition mbdToUse = mbd;
|
||||
|
||||
// Make sure bean class is actually resolved at this point, and
|
||||
// clone the bean definition in case of a dynamically resolved Class
|
||||
// which cannot be stored in the shared merged bean definition.
|
||||
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
|
||||
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
|
||||
mbdToUse = new RootBeanDefinition(mbd);
|
||||
mbdToUse.setBeanClass(resolvedClass);
|
||||
}
|
||||
|
||||
// Prepare method overrides.
|
||||
try {
|
||||
mbd.prepareMethodOverrides();
|
||||
mbdToUse.prepareMethodOverrides();
|
||||
}
|
||||
catch (BeanDefinitionValidationException ex) {
|
||||
throw new BeanDefinitionStoreException(mbd.getResourceDescription(),
|
||||
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
|
||||
beanName, "Validation of method overrides failed", ex);
|
||||
}
|
||||
|
||||
try {
|
||||
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
|
||||
Object bean = resolveBeforeInstantiation(beanName, mbd);
|
||||
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
|
||||
if (bean != null) {
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
|
||||
"BeanPostProcessor before instantiation of bean failed", ex);
|
||||
}
|
||||
|
||||
Object beanInstance = doCreateBean(beanName, mbd, args);
|
||||
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Finished creating instance of bean '" + beanName + "'");
|
||||
}
|
||||
|
|
@ -833,8 +839,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
|||
|
||||
/**
|
||||
* Obtain a "shortcut" singleton FactoryBean instance to use for a
|
||||
* {@code getObjectType()} call, without full initialization
|
||||
* of the FactoryBean.
|
||||
* {@code getObjectType()} call, without full initialization of the FactoryBean.
|
||||
* @param beanName the name of the bean
|
||||
* @param mbd the bean definition for the bean
|
||||
* @return the FactoryBean instance, or {@code null} to indicate
|
||||
|
|
@ -875,8 +880,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
|||
|
||||
/**
|
||||
* Obtain a "shortcut" non-singleton FactoryBean instance to use for a
|
||||
* {@code getObjectType()} call, without full initialization
|
||||
* of the FactoryBean.
|
||||
* {@code getObjectType()} call, without full initialization of the FactoryBean.
|
||||
* @param beanName the name of the bean
|
||||
* @param mbd the bean definition for the bean
|
||||
* @return the FactoryBean instance, or {@code null} to indicate
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
|
|
@ -1333,20 +1333,44 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
|||
}
|
||||
|
||||
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch) throws ClassNotFoundException {
|
||||
ClassLoader beanClassLoader = getBeanClassLoader();
|
||||
ClassLoader classLoaderToUse = beanClassLoader;
|
||||
if (!ObjectUtils.isEmpty(typesToMatch)) {
|
||||
// When just doing type checks (i.e. not creating an actual instance yet),
|
||||
// use the specified temporary class loader (e.g. in a weaving scenario).
|
||||
ClassLoader tempClassLoader = getTempClassLoader();
|
||||
if (tempClassLoader != null) {
|
||||
classLoaderToUse = tempClassLoader;
|
||||
if (tempClassLoader instanceof DecoratingClassLoader) {
|
||||
DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
|
||||
for (Class<?> typeToMatch : typesToMatch) {
|
||||
dcl.excludeClass(typeToMatch.getName());
|
||||
}
|
||||
}
|
||||
String className = mbd.getBeanClassName();
|
||||
return (className != null ? ClassUtils.forName(className, tempClassLoader) : null);
|
||||
}
|
||||
}
|
||||
return mbd.resolveBeanClass(getBeanClassLoader());
|
||||
String className = mbd.getBeanClassName();
|
||||
if (className != null) {
|
||||
Object evaluated = evaluateBeanDefinitionString(className, mbd);
|
||||
if (!className.equals(evaluated)) {
|
||||
// A dynamically resolved expression, supported as of 4.2...
|
||||
if (evaluated instanceof Class) {
|
||||
return (Class<?>) evaluated;
|
||||
}
|
||||
else if (evaluated instanceof String) {
|
||||
return ClassUtils.forName((String) evaluated, classLoaderToUse);
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("Invalid class name expression result: " + evaluated);
|
||||
}
|
||||
}
|
||||
// When resolving against a temporary class loader, exit early in order
|
||||
// to avoid storing the resolved Class in the bean definition.
|
||||
if (classLoaderToUse != beanClassLoader) {
|
||||
return ClassUtils.forName(className, classLoaderToUse);
|
||||
}
|
||||
}
|
||||
return mbd.resolveBeanClass(beanClassLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
|
|
@ -101,14 +101,14 @@ public class ApplicationContextExpressionTests {
|
|||
ac.registerBeanDefinition("tb0", bd0);
|
||||
|
||||
GenericBeanDefinition bd1 = new GenericBeanDefinition();
|
||||
bd1.setBeanClass(TestBean.class);
|
||||
bd1.setBeanClassName("#{tb0.class}");
|
||||
bd1.setScope("myScope");
|
||||
bd1.getConstructorArgumentValues().addGenericArgumentValue("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ");
|
||||
bd1.getConstructorArgumentValues().addGenericArgumentValue("#{mySpecialAttr}");
|
||||
ac.registerBeanDefinition("tb1", bd1);
|
||||
|
||||
GenericBeanDefinition bd2 = new GenericBeanDefinition();
|
||||
bd2.setBeanClass(TestBean.class);
|
||||
bd2.setBeanClassName("#{tb1.class.name}");
|
||||
bd2.setScope("myScope");
|
||||
bd2.getPropertyValues().add("name", "{ XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ }");
|
||||
bd2.getPropertyValues().add("age", "#{mySpecialAttr}");
|
||||
|
|
|
|||
Loading…
Reference in New Issue