📄 abstractautowirecapablebeanfactory.java
字号:
if (factoryMethodToUse == null) {
throw new BeanCreationException(
mergedBeanDefinition.getResourceDescription(), beanName,
"Cannot find matching factory method '" + mergedBeanDefinition.getFactoryMethodName() +
"' on class [" + factoryClass.getName() + "]");
}
// If we get here, we found a factory method.
Object beanInstance = this.instantiationStrategy.instantiate(
mergedBeanDefinition, beanName, this, factoryBean, factoryMethodToUse, argsToUse);
if (beanInstance == null) {
throw new BeanCreationException(
mergedBeanDefinition.getResourceDescription(), beanName,
"Factory method '" + mergedBeanDefinition.getFactoryMethodName() + "' on class [" +
factoryClass.getName() + "] returned null");
}
bw.setWrappedInstance(beanInstance);
if (logger.isDebugEnabled()) {
logger.debug("Bean '" + beanName + "' instantiated via factory method '" + factoryMethodToUse + "'");
}
return bw;
}
/**
* "autowire constructor" (with constructor arguments by type) behavior.
* Also applied if explicit constructor argument values are specified,
* matching all remaining arguments with beans from the bean factory.
* <p>This corresponds to constructor injection: In this mode, a Spring
* bean factory is able to host components that expect constructor-based
* dependency resolution.
* @param beanName name of the bean
* @param mergedBeanDefinition the bean definition for the bean
* @return BeanWrapper for the new instance
*/
protected BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mergedBeanDefinition)
throws BeansException {
ConstructorArgumentValues cargs = mergedBeanDefinition.getConstructorArgumentValues();
ConstructorArgumentValues resolvedValues = new ConstructorArgumentValues();
BeanWrapperImpl bw = new BeanWrapperImpl();
initBeanWrapper(bw);
int minNrOfArgs = 0;
if (cargs != null) {
minNrOfArgs = resolveConstructorArguments(beanName, mergedBeanDefinition, cargs, resolvedValues);
}
Constructor[] candidates = mergedBeanDefinition.getBeanClass().getDeclaredConstructors();
AutowireUtils.sortConstructors(candidates);
Constructor constructorToUse = null;
Object[] argsToUse = null;
int minTypeDiffWeight = Integer.MAX_VALUE;
for (int i = 0; i < candidates.length; i++) {
Constructor constructor = candidates[i];
if (constructorToUse != null &&
constructorToUse.getParameterTypes().length > constructor.getParameterTypes().length) {
// Already found greedy constructor that can be satisfied ->
// do not look any further, there are only less greedy constructors left.
break;
}
if (constructor.getParameterTypes().length < minNrOfArgs) {
throw new BeanCreationException(mergedBeanDefinition.getResourceDescription(), beanName,
minNrOfArgs + " constructor arguments specified but no matching constructor found in bean '" +
beanName + "' " +
"(hint: specify index and/or type arguments for simple parameters to avoid type ambiguities)");
}
// Try to resolve arguments for current constructor.
try {
Class[] argTypes = constructor.getParameterTypes();
ArgumentsHolder args = createArgumentArray(
beanName, mergedBeanDefinition, resolvedValues, bw, argTypes, "constructor");
int typeDiffWeight = args.getTypeDifferenceWeight(argTypes);
// Choose this constructor if it represents the closest match.
if (typeDiffWeight < minTypeDiffWeight) {
constructorToUse = constructor;
argsToUse = args.arguments;
minTypeDiffWeight = typeDiffWeight;
}
}
catch (UnsatisfiedDependencyException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Ignoring constructor [" + constructor + "] of bean '" + beanName +
"': " + ex.getMessage());
}
if (i == candidates.length - 1 && constructorToUse == null) {
throw ex;
}
else {
// Swallow and try next constructor.
}
}
}
if (constructorToUse == null) {
throw new BeanCreationException(
mergedBeanDefinition.getResourceDescription(), beanName, "Could not resolve matching constructor");
}
Object beanInstance = this.instantiationStrategy.instantiate(
mergedBeanDefinition, beanName, this, constructorToUse, argsToUse);
bw.setWrappedInstance(beanInstance);
if (logger.isDebugEnabled()) {
logger.debug("Bean '" + beanName + "' instantiated via constructor [" + constructorToUse + "]");
}
return bw;
}
/**
* Resolve the constructor arguments for this bean into the resolvedValues object.
* This may involve looking up other beans.
* This method is also used for handling invocations of static factory methods.
*/
private int resolveConstructorArguments(
String beanName, RootBeanDefinition mergedBeanDefinition,
ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) {
BeanDefinitionValueResolver valueResolver =
new BeanDefinitionValueResolver(this, beanName, mergedBeanDefinition);
int minNrOfArgs = cargs.getArgumentCount();
for (Iterator it = cargs.getIndexedArgumentValues().entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
int index = ((Integer) entry.getKey()).intValue();
if (index < 0) {
throw new BeanCreationException(mergedBeanDefinition.getResourceDescription(), beanName,
"Invalid constructor argument index: " + index);
}
if (index > minNrOfArgs) {
minNrOfArgs = index + 1;
}
String argName = "constructor argument with index " + index;
ConstructorArgumentValues.ValueHolder valueHolder =
(ConstructorArgumentValues.ValueHolder) entry.getValue();
Object resolvedValue = valueResolver.resolveValueIfNecessary(argName, valueHolder.getValue());
resolvedValues.addIndexedArgumentValue(index, resolvedValue, valueHolder.getType());
}
for (Iterator it = cargs.getGenericArgumentValues().iterator(); it.hasNext();) {
ConstructorArgumentValues.ValueHolder valueHolder =
(ConstructorArgumentValues.ValueHolder) it.next();
String argName = "constructor argument";
Object resolvedValue = valueResolver.resolveValueIfNecessary(argName, valueHolder.getValue());
resolvedValues.addGenericArgumentValue(resolvedValue, valueHolder.getType());
}
return minNrOfArgs;
}
/**
* Create an array of arguments to invoke a constructor or factory method,
* given the resolved constructor argument values.
*/
private ArgumentsHolder createArgumentArray(
String beanName, RootBeanDefinition mergedBeanDefinition, ConstructorArgumentValues resolvedValues,
BeanWrapperImpl bw, Class[] argTypes, String methodType)
throws UnsatisfiedDependencyException {
ArgumentsHolder args = new ArgumentsHolder(argTypes.length);
Set usedValueHolders = new HashSet(argTypes.length);
for (int j = 0; j < argTypes.length; j++) {
// Try to find matching constructor argument value, either indexed or generic.
ConstructorArgumentValues.ValueHolder valueHolder =
resolvedValues.getArgumentValue(j, argTypes[j], usedValueHolders);
// If we couldn't find a direct match and are not supposed to autowire,
// let's try the next generic, untyped argument value as fallback:
// it could match after type conversion (for example, String -> int).
if (valueHolder == null &&
mergedBeanDefinition.getResolvedAutowireMode() != RootBeanDefinition.AUTOWIRE_CONSTRUCTOR) {
valueHolder = resolvedValues.getGenericArgumentValue(null, usedValueHolders);
}
if (valueHolder != null) {
// We found a potential match - let's give it a try.
// Do not consider the same value definition multiple times!
usedValueHolders.add(valueHolder);
args.rawArguments[j] = valueHolder.getValue();
try {
args.arguments[j] = doTypeConversionIfNecessary(args.rawArguments[j], argTypes[j], bw);
}
catch (TypeMismatchException ex) {
throw new UnsatisfiedDependencyException(
mergedBeanDefinition.getResourceDescription(), beanName, j, argTypes[j],
"Could not convert " + methodType + " argument value [" + valueHolder.getValue() +
"] to required type [" + argTypes[j].getName() + "]: " + ex.getMessage());
}
}
else {
// No explicit match found: we're either supposed to autowire or
// have to fail creating an argument array for the given constructor.
if (mergedBeanDefinition.getResolvedAutowireMode() != RootBeanDefinition.AUTOWIRE_CONSTRUCTOR) {
throw new UnsatisfiedDependencyException(
mergedBeanDefinition.getResourceDescription(), beanName, j, argTypes[j],
"Ambiguous " + methodType + " argument types - " +
"did you specify the correct bean references as " + methodType + " arguments?");
}
Map matchingBeans = findMatchingBeans(argTypes[j]);
if (matchingBeans == null || matchingBeans.size() != 1) {
int matchingBeansCount = (matchingBeans != null ? matchingBeans.size() : 0);
throw new UnsatisfiedDependencyException(
mergedBeanDefinition.getResourceDescription(), beanName, j, argTypes[j],
"There are " + matchingBeansCount + " beans of type [" + argTypes[j] +
"] for autowiring " + methodType + ". There should have been 1 to be able to " +
"autowire " + methodType + " of bean '" + beanName + "'.");
}
String autowiredBeanName = (String) matchingBeans.keySet().iterator().next();
Object autowiredBean = matchingBeans.values().iterator().next();
args.rawArguments[j] = autowiredBean;
args.arguments[j] = autowiredBean;
if (mergedBeanDefinition.isSingleton()) {
registerDependentBean(autowiredBeanName, beanName);
}
if (logger.isDebugEnabled()) {
logger.debug("Autowiring by type from bean name '" + beanName +
"' via " + methodType + " to bean named '" + autowiredBeanName + "'");
}
}
}
return args;
}
/**
* Populate the bean instance in the given BeanWrapper with the property values
* from the bean definition.
* @param beanName name of the bean
* @param mergedBeanDefinition the bean definition for the bean
* @param bw BeanWrapper with bean instance
*/
protected void populateBean(String beanName, RootBeanDefinition mergedBeanDefinition, BeanWrapper bw)
throws BeansException {
PropertyValues pvs = mergedBeanDefinition.getPropertyValues();
if (mergedBeanDefinition.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mergedBeanDefinition.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues mpvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (mergedBeanDefinition.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mergedBeanDefinition, bw, mpvs);
}
// Add property values based on autowire by type if applicable.
if (mergedBeanDefinition.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mergedBeanDefinition, bw, mpvs);
}
pvs = mpvs;
}
checkDependencies(beanName, mergedBeanDefinition, bw, pvs);
applyPropertyValues(beanName, mergedBeanDefinition, bw, pvs);
}
/**
* Fill in any missing property values with references to
* other beans in this factory if autowire is set to "byName".
* @param beanName name of the bean we're wiring up.
* Useful for debugging messages; not used functionally.
* @param mergedBeanDefinition bean definition to update through autowiring
* @param bw BeanWrapper from which we can obtain information about the bean
* @param pvs the PropertyValues to register wired objects with
*/
protected void autowireByName(
String beanName, RootBeanDefinition mergedBeanDefinition, BeanWrapper bw, MutablePropertyValues pvs)
throws BeansException {
String[] propertyNames = unsatisfiedNonSimpleProperties(mergedBeanDefinition, bw);
for (int i = 0; i < propertyNames.length; i++) {
String propertyName = propertyNames[i];
if (containsBean(propertyName)) {
Object bean = getBean(propertyName);
pvs.addPropertyValue(propertyName, bean);
if (mergedBeanDefinition.isSingleton()) {
registerDependentBean(propertyName, beanName);
}
if (logger.isDebugEnabled()) {
logger.debug("Added autowiring by name from bean name '" + beanName +
"' via property '" + propertyName + "' to bean named '" + propertyName + "'");
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Not autowiring property '" + propertyName + "' of bean '" + beanName +
"' by name: no matching bean found");
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -