@Test public void testAutowiredFieldDoesNotResolveWithMultipleQualifierValuesAndMultipleMatchingCandidates() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue(JUERGEN); RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(TestQualifierWithMultipleAttributes.class); qualifier.setAttribute("number", 123); person1.addQualifier(qualifier); ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); cavs2.addGenericArgumentValue(MARK); RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); AutowireCandidateQualifier qualifier2 = new AutowireCandidateQualifier(TestQualifierWithMultipleAttributes.class); qualifier2.setAttribute("number", 123); qualifier2.setAttribute("value", "default"); person2.addQualifier(qualifier2); context.registerBeanDefinition(JUERGEN, person1); context.registerBeanDefinition(MARK, person2); context.registerBeanDefinition( "autowired", new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class)); AnnotationConfigUtils.registerAnnotationConfigProcessors(context); try { context.refresh(); fail("expected BeanCreationException"); } catch (BeanCreationException e) { assertTrue(e.getRootCause() instanceof NoSuchBeanDefinitionException); assertEquals("autowired", e.getBeanName()); } }
@Test public void testAutowiredFieldDoesNotResolveWithBaseQualifierAndNonDefaultValueAndMultipleMatchingCandidates() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue("the real juergen"); RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); person1.addQualifier(new AutowireCandidateQualifier(Qualifier.class, "juergen")); ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); cavs2.addGenericArgumentValue("juergen imposter"); RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); person2.addQualifier(new AutowireCandidateQualifier(Qualifier.class, "juergen")); context.registerBeanDefinition("juergen1", person1); context.registerBeanDefinition("juergen2", person2); context.registerBeanDefinition( "autowired", new RootBeanDefinition( QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean.class)); AnnotationConfigUtils.registerAnnotationConfigProcessors(context); try { context.refresh(); fail("expected BeanCreationException"); } catch (BeanCreationException e) { assertTrue(e instanceof UnsatisfiedDependencyException); assertEquals("autowired", e.getBeanName()); } }
@Test public void testAutowiredFieldResolvesWithMultipleQualifierValuesAndExplicitDefaultValue() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue(JUERGEN); RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(TestQualifierWithMultipleAttributes.class); qualifier.setAttribute("number", 456); person1.addQualifier(qualifier); ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); cavs2.addGenericArgumentValue(MARK); RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); AutowireCandidateQualifier qualifier2 = new AutowireCandidateQualifier(TestQualifierWithMultipleAttributes.class); qualifier2.setAttribute("number", 123); qualifier2.setAttribute("value", "default"); person2.addQualifier(qualifier2); context.registerBeanDefinition(JUERGEN, person1); context.registerBeanDefinition(MARK, person2); context.registerBeanDefinition( "autowired", new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class)); AnnotationConfigUtils.registerAnnotationConfigProcessors(context); context.refresh(); QualifiedFieldWithMultipleAttributesTestBean bean = (QualifiedFieldWithMultipleAttributesTestBean) context.getBean("autowired"); assertEquals(MARK, bean.getPerson().getName()); }
/** * Determine whether the bean definition with the given name matches the given type. * * @param beanName the name of the bean to check * @param type class or interface to match, or <code>null</code> for all bean names * @return whether the type matches * @see RootBeanDefinition#hasBeanClass * @see RootBeanDefinition#getBeanClass */ private boolean isBeanDefinitionTypeMatch(String beanName, Class type) { if (type == null) { return true; } RootBeanDefinition rbd = getMergedBeanDefinition(beanName, false); return (rbd.hasBeanClass() && type.isAssignableFrom(rbd.getBeanClass())); }
@Test public void testAutowiredFieldDoesNotResolveCandidateWithDefaultValueAndConflictingValueOnBeanDefinition() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue(JUERGEN); RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); // qualifier added, and non-default value specified person1.addQualifier( new AutowireCandidateQualifier(TestQualifierWithDefaultValue.class, "not the default")); ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); cavs2.addGenericArgumentValue(MARK); RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); context.registerBeanDefinition(JUERGEN, person1); context.registerBeanDefinition(MARK, person2); context.registerBeanDefinition( "autowired", new RootBeanDefinition(QualifiedFieldWithDefaultValueTestBean.class)); AnnotationConfigUtils.registerAnnotationConfigProcessors(context); try { context.refresh(); fail("expected BeanCreationException"); } catch (BeanCreationException e) { assertTrue(e.getRootCause() instanceof NoSuchBeanDefinitionException); assertEquals("autowired", e.getBeanName()); } }
/** * Resolve the factory method in the specified bean definition, if possible. {@link * RootBeanDefinition#getResolvedFactoryMethod()} can be checked for the result. * * @param mbd the bean definition to check */ public void resolveFactoryMethodIfPossible(RootBeanDefinition mbd) { Class<?> factoryClass; boolean isStatic; if (mbd.getFactoryBeanName() != null) { factoryClass = this.beanFactory.getType(mbd.getFactoryBeanName()); isStatic = false; } else { factoryClass = mbd.getBeanClass(); isStatic = true; } factoryClass = ClassUtils.getUserClass(factoryClass); Method[] candidates = getCandidateMethods(factoryClass, mbd); Method uniqueCandidate = null; for (Method candidate : candidates) { if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) { if (uniqueCandidate == null) { uniqueCandidate = candidate; } else if (!Arrays.equals( uniqueCandidate.getParameterTypes(), candidate.getParameterTypes())) { uniqueCandidate = null; break; } } } synchronized (mbd.constructorArgumentLock) { mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate; } }
public void storeCache(RootBeanDefinition mbd, Object constructorOrFactoryMethod) { synchronized (mbd.constructorArgumentLock) { mbd.resolvedConstructorOrFactoryMethod = constructorOrFactoryMethod; mbd.constructorArgumentsResolved = true; if (this.resolveNecessary) { mbd.preparedConstructorArguments = this.preparedArguments; } else { mbd.resolvedConstructorArguments = this.arguments; } } }
@Test public void testAutowiredFieldWithSingleQualifiedCandidate() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs = new ConstructorArgumentValues(); cavs.addGenericArgumentValue(JUERGEN); RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null); person.addQualifier(new AutowireCandidateQualifier(TestQualifier.class)); context.registerBeanDefinition(JUERGEN, person); context.registerBeanDefinition( "autowired", new RootBeanDefinition(QualifiedFieldTestBean.class)); AnnotationConfigUtils.registerAnnotationConfigProcessors(context); context.refresh(); QualifiedFieldTestBean bean = (QualifiedFieldTestBean) context.getBean("autowired"); assertEquals(JUERGEN, bean.getPerson().getName()); }
/** * Resolve the constructor arguments for this bean into the resolvedValues object. This may * involve looking up other beans. * * <p>This method is also used for handling invocations of static factory methods. */ private int resolveConstructorArguments( String beanName, RootBeanDefinition mbd, BeanWrapper bw, ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) { TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ? this.beanFactory.getCustomTypeConverter() : bw); BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter); int minNrOfArgs = cargs.getArgumentCount(); for (Map.Entry<Integer, ConstructorArgumentValues.ValueHolder> entry : cargs.getIndexedArgumentValues().entrySet()) { int index = entry.getKey(); if (index < 0) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid constructor argument index: " + index); } if (index > minNrOfArgs) { minNrOfArgs = index + 1; } ConstructorArgumentValues.ValueHolder valueHolder = entry.getValue(); if (valueHolder.isConverted()) { resolvedValues.addIndexedArgumentValue(index, valueHolder); } else { Object resolvedValue = valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue()); ConstructorArgumentValues.ValueHolder resolvedValueHolder = new ConstructorArgumentValues.ValueHolder( resolvedValue, valueHolder.getType(), valueHolder.getName()); resolvedValueHolder.setSource(valueHolder); resolvedValues.addIndexedArgumentValue(index, resolvedValueHolder); } } for (ConstructorArgumentValues.ValueHolder valueHolder : cargs.getGenericArgumentValues()) { if (valueHolder.isConverted()) { resolvedValues.addGenericArgumentValue(valueHolder); } else { Object resolvedValue = valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue()); ConstructorArgumentValues.ValueHolder resolvedValueHolder = new ConstructorArgumentValues.ValueHolder( resolvedValue, valueHolder.getType(), valueHolder.getName()); resolvedValueHolder.setSource(valueHolder); resolvedValues.addGenericArgumentValue(resolvedValueHolder); } } return minNrOfArgs; }
@Test public void testAutowiredMethodParameterResolvesQualifiedCandidate() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue(JUERGEN); RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); person1.addQualifier(new AutowireCandidateQualifier(TestQualifier.class)); ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); cavs2.addGenericArgumentValue(MARK); RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); context.registerBeanDefinition(JUERGEN, person1); context.registerBeanDefinition(MARK, person2); context.registerBeanDefinition( "autowired", new RootBeanDefinition(QualifiedMethodParameterTestBean.class)); AnnotationConfigUtils.registerAnnotationConfigProcessors(context); context.refresh(); QualifiedMethodParameterTestBean bean = (QualifiedMethodParameterTestBean) context.getBean("autowired"); assertEquals(JUERGEN, bean.getPerson().getName()); }
public void preInstantiateSingletons() throws BeansException { if (logger.isInfoEnabled()) { logger.info("Pre-instantiating singletons in factory [" + this + "]"); } try { for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext(); ) { String beanName = (String) it.next(); if (containsBeanDefinition(beanName)) { RootBeanDefinition bd = getMergedBeanDefinition(beanName, false); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (bd.hasBeanClass() && FactoryBean.class.isAssignableFrom(bd.getBeanClass())) { FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName); if (factory.isSingleton()) { getBean(beanName); } } else { getBean(beanName); } } } } } catch (BeansException ex) { // destroy already created singletons to avoid dangling resources try { destroySingletons(); } catch (Throwable ex2) { logger.error( "Pre-instantiating singletons failed, " + "and couldn't destroy already created singletons", ex2); } throw ex; } }
/** Resolve the prepared arguments stored in the given bean definition. */ private Object[] resolvePreparedArguments( String beanName, RootBeanDefinition mbd, BeanWrapper bw, Member methodOrCtor, Object[] argsToResolve) { Class<?>[] paramTypes = (methodOrCtor instanceof Method ? ((Method) methodOrCtor).getParameterTypes() : ((Constructor<?>) methodOrCtor).getParameterTypes()); TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ? this.beanFactory.getCustomTypeConverter() : bw); BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter); Object[] resolvedArgs = new Object[argsToResolve.length]; for (int argIndex = 0; argIndex < argsToResolve.length; argIndex++) { Object argValue = argsToResolve[argIndex]; MethodParameter methodParam = MethodParameter.forMethodOrConstructor(methodOrCtor, argIndex); GenericTypeResolver.resolveParameterType(methodParam, methodOrCtor.getDeclaringClass()); if (argValue instanceof AutowiredArgumentMarker) { argValue = resolveAutowiredArgument(methodParam, beanName, null, converter); } else if (argValue instanceof BeanMetadataElement) { argValue = valueResolver.resolveValueIfNecessary("constructor argument", argValue); } else if (argValue instanceof String) { argValue = this.beanFactory.evaluateBeanDefinitionString((String) argValue, mbd); } Class<?> paramType = paramTypes[argIndex]; try { resolvedArgs[argIndex] = converter.convertIfNecessary(argValue, paramType, methodParam); } catch (TypeMismatchException ex) { String methodType = (methodOrCtor instanceof Constructor ? "constructor" : "factory method"); throw new UnsatisfiedDependencyException( mbd.getResourceDescription(), beanName, argIndex, paramType, "Could not convert " + methodType + " argument value of type [" + ObjectUtils.nullSafeClassName(argValue) + "] to required type [" + paramType.getName() + "]: " + ex.getMessage()); } } return resolvedArgs; }
@Test public void testAutowiredFieldResolvesWithDefaultValueAndExplicitDefaultValueOnBeanDefinition() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue(JUERGEN); RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); // qualifier added, and value matches the default person1.addQualifier( new AutowireCandidateQualifier(TestQualifierWithDefaultValue.class, "default")); ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); cavs2.addGenericArgumentValue(MARK); RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); context.registerBeanDefinition(JUERGEN, person1); context.registerBeanDefinition(MARK, person2); context.registerBeanDefinition( "autowired", new RootBeanDefinition(QualifiedFieldWithDefaultValueTestBean.class)); AnnotationConfigUtils.registerAnnotationConfigProcessors(context); context.refresh(); QualifiedFieldWithDefaultValueTestBean bean = (QualifiedFieldWithDefaultValueTestBean) context.getBean("autowired"); assertEquals(JUERGEN, bean.getPerson().getName()); }
/** * Retrieve all candidate methods for the given class, considering the {@link * RootBeanDefinition#isNonPublicAccessAllowed()} flag. Called as the starting point for factory * method determination. */ private Method[] getCandidateMethods(final Class<?> factoryClass, final RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { return AccessController.doPrivileged( new PrivilegedAction<Method[]>() { @Override public Method[] run() { return (mbd.isNonPublicAccessAllowed() ? ReflectionUtils.getAllDeclaredMethods(factoryClass) : factoryClass.getMethods()); } }); } else { return (mbd.isNonPublicAccessAllowed() ? ReflectionUtils.getAllDeclaredMethods(factoryClass) : factoryClass.getMethods()); } }
/** * Resolve an inner bean definition. * * @param argName the name of the argument that the inner bean is defined for * @param innerBeanName the name of the inner bean * @param innerBd the bean definition for the inner bean * @return the resolved inner bean instance */ private Object resolveInnerBean(Object argName, String innerBeanName, BeanDefinition innerBd) { RootBeanDefinition mbd = null; try { mbd = this.beanFactory.getMergedBeanDefinition(innerBeanName, innerBd, this.beanDefinition); // Check given bean name whether it is unique. If not already unique, // add counter - increasing the counter until the name is unique. String actualInnerBeanName = innerBeanName; if (mbd.isSingleton()) { actualInnerBeanName = adaptInnerBeanName(innerBeanName); } this.beanFactory.registerContainedBean(actualInnerBeanName, this.beanName); // Guarantee initialization of beans that the inner bean depends on. String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dependsOnBean : dependsOn) { this.beanFactory.registerDependentBean(dependsOnBean, actualInnerBeanName); this.beanFactory.getBean(dependsOnBean); } } // Actually create the inner bean instance now... Object innerBean = this.beanFactory.createBean(actualInnerBeanName, mbd, null); if (innerBean instanceof FactoryBean) { boolean synthetic = mbd.isSynthetic(); return this.beanFactory.getObjectFromFactoryBean( (FactoryBean<?>) innerBean, actualInnerBeanName, !synthetic); } else { return innerBean; } } catch (BeansException ex) { throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Cannot create inner bean '" + innerBeanName + "' " + (mbd != null && mbd.getBeanClassName() != null ? "of type [" + mbd.getBeanClassName() + "] " : "") + "while setting " + argName, ex); } }
public String[] getBeanNamesForType( Class type, boolean includePrototypes, boolean includeFactoryBeans) { List result = new ArrayList(); // Check all bean definitions. for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext(); ) { String beanName = (String) it.next(); RootBeanDefinition rbd = getMergedBeanDefinition(beanName, false); // Only check bean definition if it is complete. if (!rbd.isAbstract()) { // In case of FactoryBean, match object created by FactoryBean. boolean isFactoryBean = rbd.hasBeanClass() && FactoryBean.class.isAssignableFrom(rbd.getBeanClass()); if (isFactoryBean || rbd.getFactoryBeanName() != null) { if (includeFactoryBeans && (includePrototypes || isSingleton(beanName)) && isBeanTypeMatch(beanName, type)) { result.add(beanName); // Match found for this bean: do not match FactoryBean itself anymore. continue; } // We're done for anything but a full FactoryBean. if (!isFactoryBean) { continue; } // In case of FactoryBean, try to match FactoryBean itself next. beanName = FACTORY_BEAN_PREFIX + beanName; } // Match raw bean instance (might be raw FactoryBean). if ((includePrototypes || rbd.isSingleton()) && isBeanTypeMatch(beanName, type)) { result.add(beanName); } } } // Check singletons too, to catch manually registered singletons. String[] singletonNames = getSingletonNames(); for (int i = 0; i < singletonNames.length; i++) { String beanName = singletonNames[i]; // Only check if manually registered. if (!containsBeanDefinition(beanName)) { // In case of FactoryBean, match object created by FactoryBean. if (isFactoryBean(beanName)) { if (includeFactoryBeans && (includePrototypes || isSingleton(beanName)) && isBeanTypeMatch(beanName, type)) { result.add(beanName); // Match found for this bean: do not match FactoryBean itself anymore. continue; } // In case of FactoryBean, try to match FactoryBean itself next. beanName = FACTORY_BEAN_PREFIX + beanName; } // Match raw bean instance (might be raw FactoryBean). if (isBeanTypeMatch(beanName, type)) { result.add(beanName); } } } return (String[]) result.toArray(new String[result.size()]); }
/** * Create an array of arguments to invoke a constructor or factory method, given the resolved * constructor argument values. */ private ArgumentsHolder createArgumentArray( String beanName, RootBeanDefinition mbd, ConstructorArgumentValues resolvedValues, BeanWrapper bw, Class<?>[] paramTypes, String[] paramNames, Object methodOrCtor, boolean autowiring) throws UnsatisfiedDependencyException { String methodType = (methodOrCtor instanceof Constructor ? "constructor" : "factory method"); TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ? this.beanFactory.getCustomTypeConverter() : bw); ArgumentsHolder args = new ArgumentsHolder(paramTypes.length); Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<ConstructorArgumentValues.ValueHolder>(paramTypes.length); Set<String> autowiredBeanNames = new LinkedHashSet<String>(4); for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) { Class<?> paramType = paramTypes[paramIndex]; String paramName = (paramNames != null ? paramNames[paramIndex] : null); // Try to find matching constructor argument value, either indexed or generic. ConstructorArgumentValues.ValueHolder valueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, paramName, 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 && !autowiring) { valueHolder = resolvedValues.getGenericArgumentValue(null, 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); Object originalValue = valueHolder.getValue(); Object convertedValue; if (valueHolder.isConverted()) { convertedValue = valueHolder.getConvertedValue(); args.preparedArguments[paramIndex] = convertedValue; } else { ConstructorArgumentValues.ValueHolder sourceHolder = (ConstructorArgumentValues.ValueHolder) valueHolder.getSource(); Object sourceValue = sourceHolder.getValue(); try { convertedValue = converter.convertIfNecessary( originalValue, paramType, MethodParameter.forMethodOrConstructor(methodOrCtor, paramIndex)); // TODO re-enable once race condition has been found (SPR-7423) /* if (originalValue == sourceValue || sourceValue instanceof TypedStringValue) { // Either a converted value or still the original one: store converted value. sourceHolder.setConvertedValue(convertedValue); args.preparedArguments[paramIndex] = convertedValue; } else { */ args.resolveNecessary = true; args.preparedArguments[paramIndex] = sourceValue; // } } catch (TypeMismatchException ex) { throw new UnsatisfiedDependencyException( mbd.getResourceDescription(), beanName, paramIndex, paramType, "Could not convert " + methodType + " argument value of type [" + ObjectUtils.nullSafeClassName(valueHolder.getValue()) + "] to required type [" + paramType.getName() + "]: " + ex.getMessage()); } } args.arguments[paramIndex] = convertedValue; args.rawArguments[paramIndex] = originalValue; } else { // No explicit match found: we're either supposed to autowire or // have to fail creating an argument array for the given constructor. if (!autowiring) { throw new UnsatisfiedDependencyException( mbd.getResourceDescription(), beanName, paramIndex, paramType, "Ambiguous " + methodType + " argument types - " + "did you specify the correct bean references as " + methodType + " arguments?"); } try { MethodParameter param = MethodParameter.forMethodOrConstructor(methodOrCtor, paramIndex); Object autowiredArgument = resolveAutowiredArgument(param, beanName, autowiredBeanNames, converter); args.rawArguments[paramIndex] = autowiredArgument; args.arguments[paramIndex] = autowiredArgument; args.preparedArguments[paramIndex] = new AutowiredArgumentMarker(); args.resolveNecessary = true; } catch (BeansException ex) { throw new UnsatisfiedDependencyException( mbd.getResourceDescription(), beanName, paramIndex, paramType, ex); } } } for (String autowiredBeanName : autowiredBeanNames) { this.beanFactory.registerDependentBean(autowiredBeanName, beanName); if (this.beanFactory.logger.isDebugEnabled()) { this.beanFactory.logger.debug( "Autowiring by type from bean name '" + beanName + "' via " + methodType + " to bean named '" + autowiredBeanName + "'"); } } return args; }
/** * Instantiate the bean using a named factory method. The method may be static, if the bean * definition parameter specifies a class, rather than a "factory-bean", or an instance variable * on a factory object itself configured using Dependency Injection. * * <p>Implementation requires iterating over the static or instance methods with the name * specified in the RootBeanDefinition (the method may be overloaded) and trying to match with the * parameters. We don't have the types attached to constructor args, so trial and error is the * only way to go here. The explicitArgs array may contain argument values passed in * programmatically via the corresponding getBean method. * * @param beanName the name of the bean * @param mbd the merged bean definition for the bean * @param explicitArgs argument values passed in programmatically via the getBean method, or * {@code null} if none (-> use constructor argument values from bean definition) * @return a BeanWrapper for the new instance */ public BeanWrapper instantiateUsingFactoryMethod( final String beanName, final RootBeanDefinition mbd, final Object[] explicitArgs) { BeanWrapperImpl bw = new BeanWrapperImpl(); this.beanFactory.initBeanWrapper(bw); Object factoryBean; Class<?> factoryClass; boolean isStatic; String factoryBeanName = mbd.getFactoryBeanName(); if (factoryBeanName != null) { if (factoryBeanName.equals(beanName)) { throw new BeanDefinitionStoreException( mbd.getResourceDescription(), beanName, "factory-bean reference points back to the same bean definition"); } factoryBean = this.beanFactory.getBean(factoryBeanName); if (factoryBean == null) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "factory-bean '" + factoryBeanName + "' (or a BeanPostProcessor involved) returned null"); } if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) { throw new IllegalStateException( "About-to-be-created singleton instance implicitly appeared " + "through the creation of the factory bean that its bean definition points to"); } factoryClass = factoryBean.getClass(); isStatic = false; } else { // It's a static factory method on the bean class. if (!mbd.hasBeanClass()) { throw new BeanDefinitionStoreException( mbd.getResourceDescription(), beanName, "bean definition declares neither a bean class nor a factory-bean reference"); } factoryBean = null; factoryClass = mbd.getBeanClass(); isStatic = true; } Method factoryMethodToUse = null; ArgumentsHolder argsHolderToUse = null; Object[] argsToUse = null; if (explicitArgs != null) { argsToUse = explicitArgs; } else { Object[] argsToResolve = null; synchronized (mbd.constructorArgumentLock) { factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod; if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) { // Found a cached factory method... argsToUse = mbd.resolvedConstructorArguments; if (argsToUse == null) { argsToResolve = mbd.preparedConstructorArguments; } } } if (argsToResolve != null) { argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve); } } if (factoryMethodToUse == null || argsToUse == null) { // Need to determine the factory method... // Try all methods with this name to see if they match the given arguments. factoryClass = ClassUtils.getUserClass(factoryClass); Method[] rawCandidates = getCandidateMethods(factoryClass, mbd); List<Method> candidateSet = new ArrayList<Method>(); for (Method candidate : rawCandidates) { if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) { candidateSet.add(candidate); } } Method[] candidates = candidateSet.toArray(new Method[candidateSet.size()]); AutowireUtils.sortFactoryMethods(candidates); ConstructorArgumentValues resolvedValues = null; boolean autowiring = (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR); int minTypeDiffWeight = Integer.MAX_VALUE; Set<Method> ambiguousFactoryMethods = null; int minNrOfArgs; if (explicitArgs != null) { minNrOfArgs = explicitArgs.length; } else { // We don't have arguments passed in programmatically, so we need to resolve the // arguments specified in the constructor arguments held in the bean definition. ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues(); resolvedValues = new ConstructorArgumentValues(); minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); } List<Exception> causes = null; for (int i = 0; i < candidates.length; i++) { Method candidate = candidates[i]; Class<?>[] paramTypes = candidate.getParameterTypes(); if (paramTypes.length >= minNrOfArgs) { ArgumentsHolder argsHolder; if (resolvedValues != null) { // Resolved constructor arguments: type conversion and/or autowiring necessary. try { String[] paramNames = null; ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer(); if (pnd != null) { paramNames = pnd.getParameterNames(candidate); } argsHolder = createArgumentArray( beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring); } catch (UnsatisfiedDependencyException ex) { if (this.beanFactory.logger.isTraceEnabled()) { this.beanFactory.logger.trace( "Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex); } if (i == candidates.length - 1 && argsHolderToUse == null) { if (causes != null) { for (Exception cause : causes) { this.beanFactory.onSuppressedException(cause); } } throw ex; } else { // Swallow and try next overloaded factory method. if (causes == null) { causes = new LinkedList<Exception>(); } causes.add(ex); continue; } } } else { // Explicit arguments given -> arguments length must match exactly. if (paramTypes.length != explicitArgs.length) { continue; } argsHolder = new ArgumentsHolder(explicitArgs); } int typeDiffWeight = (mbd.isLenientConstructorResolution() ? argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes)); // Choose this factory method if it represents the closest match. if (typeDiffWeight < minTypeDiffWeight) { factoryMethodToUse = candidate; argsHolderToUse = argsHolder; argsToUse = argsHolder.arguments; minTypeDiffWeight = typeDiffWeight; ambiguousFactoryMethods = null; } // Find out about ambiguity: In case of the same type difference weight // for methods with the same number of parameters, collect such candidates // and eventually raise an ambiguity exception. // However, only perform that check in non-lenient constructor resolution mode, // and explicitly ignore overridden methods (with the same parameter signature). else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight && !mbd.isLenientConstructorResolution() && paramTypes.length == factoryMethodToUse.getParameterTypes().length && !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) { if (ambiguousFactoryMethods == null) { ambiguousFactoryMethods = new LinkedHashSet<Method>(); ambiguousFactoryMethods.add(factoryMethodToUse); } ambiguousFactoryMethods.add(candidate); } } } if (factoryMethodToUse == null) { List<String> argTypes = new ArrayList<String>(minNrOfArgs); if (explicitArgs != null) { for (Object arg : explicitArgs) { argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null"); } } else { Set<ValueHolder> valueHolders = new LinkedHashSet<ValueHolder>(resolvedValues.getArgumentCount()); valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values()); valueHolders.addAll(resolvedValues.getGenericArgumentValues()); for (ValueHolder value : valueHolders) { String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) : (value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null")); argTypes.add(argType); } } String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes); throw new BeanCreationException( mbd.getResourceDescription(), beanName, "No matching factory method found: " + (mbd.getFactoryBeanName() != null ? "factory bean '" + mbd.getFactoryBeanName() + "'; " : "") + "factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " + "Check that a method with the specified name " + (minNrOfArgs > 0 ? "and arguments " : "") + "exists and that it is " + (isStatic ? "static" : "non-static") + "."); } else if (void.class.equals(factoryMethodToUse.getReturnType())) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid factory method '" + mbd.getFactoryMethodName() + "': needs to have a non-void return type!"); } else if (ambiguousFactoryMethods != null) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Ambiguous factory method matches found in bean '" + beanName + "' " + "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " + ambiguousFactoryMethods); } if (explicitArgs == null && argsHolderToUse != null) { argsHolderToUse.storeCache(mbd, factoryMethodToUse); } } try { Object beanInstance; if (System.getSecurityManager() != null) { final Object fb = factoryBean; final Method factoryMethod = factoryMethodToUse; final Object[] args = argsToUse; beanInstance = AccessController.doPrivileged( new PrivilegedAction<Object>() { @Override public Object run() { return beanFactory .getInstantiationStrategy() .instantiate(mbd, beanName, beanFactory, fb, factoryMethod, args); } }, beanFactory.getAccessControlContext()); } else { beanInstance = this.beanFactory .getInstantiationStrategy() .instantiate( mbd, beanName, this.beanFactory, factoryBean, factoryMethodToUse, argsToUse); } if (beanInstance == null) { return null; } bw.setWrappedInstance(beanInstance); return bw; } catch (Throwable ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Bean instantiation via factory method failed", ex); } }
/** * 带有参数的实例化Bean方法,主要完成的功能如下: 1. 构造函数参数的确定 1)根据explicitArgs参数判断 2)从缓存中获取 3)从配置文件获取 2. 构造函数的确定 3. * 根据确定的构造函数转换对应的参数类型 4. 构造函数不确定性的验证 5. 根据实例化策略以及得到的构造函数和构造函数参数实例化bean */ public BeanWrapper autowireConstructor( final String beanName, final RootBeanDefinition mbd, Constructor<?>[] chosenCtors, final Object[] explicitArgs) { BeanWrapperImpl bw = new BeanWrapperImpl(); this.beanFactory.initBeanWrapper(bw); // 定义选取的构造函数 Constructor<?> constructorToUse = null; // 定义选取的构造函数参数 ArgumentsHolder argsHolderToUse = null; Object[] argsToUse = null; // 如果getBean调用时指定了方法参数,则直接使用 if (explicitArgs != null) { argsToUse = explicitArgs; } // getBean方法未指定参数,则从配置文件中解析 else { Object[] argsToResolve = null; // 尝试从缓存中获取bean的构造函数以及参数 // 解析bean定义的构造函数较为耗时,因此在完成解析后会将解析后的构造函数以及参数放入BeanDefinition中的相关字段作为缓存 // mbd.resolvedConstructorOrFactoryMethod存放的是构造函数 // mbd.resolvedConstructorArguments存放的是处理后的构造函数参数 // mbd.preparedConstructorArguments存放的是原生的构造函数参数(参数类型未经过处理) synchronized (mbd.constructorArgumentLock) { constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod; if (constructorToUse != null && mbd.constructorArgumentsResolved) { // Found a cached constructor... argsToUse = mbd.resolvedConstructorArguments; if (argsToUse == null) { argsToResolve = mbd.preparedConstructorArguments; } } } // 如果缓存中存在 if (argsToResolve != null) { // 解析参数类型,将构造参数的类型转换为最终的类型 // eg: 构造函数A(int, int) // 通过此方法后就会把配置中的("1", "1")转换为(1, 1) argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve); } } // 缓存中不存在 if (constructorToUse == null) { // Need to resolve the constructor. boolean autowiring = (chosenCtors != null || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR); // 存放解析后的构造函数参数的值 ConstructorArgumentValues resolvedValues = null; int minNrOfArgs; if (explicitArgs != null) { minNrOfArgs = explicitArgs.length; } else { // 提取配置文件中的构造函数参数 ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues(); resolvedValues = new ConstructorArgumentValues(); minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); } // Take specified constructors, if any. // 获取bean的class类的所有构造函数 Constructor<?>[] candidates = chosenCtors; if (candidates == null) { Class<?> beanClass = mbd.getBeanClass(); try { candidates = (mbd.isNonPublicAccessAllowed() ? beanClass.getDeclaredConstructors() : beanClass.getConstructors()); } catch (Throwable ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Resolution of declared constructors on bean Class [" + beanClass.getName() + "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex); } } // 排序给定的构造函数,public构造函数优先,参数数量降序 AutowireUtils.sortConstructors(candidates); int minTypeDiffWeight = Integer.MAX_VALUE; Set<Constructor<?>> ambiguousConstructors = null; LinkedList<UnsatisfiedDependencyException> causes = null; for (int i = 0; i < candidates.length; i++) { Constructor<?> candidate = candidates[i]; Class<?>[] paramTypes = candidate.getParameterTypes(); // 如果已经找到选用的构造函数,并且构造函数所需的参数个数小于配置的构造函数参数个数则终止,因为构造函数已经按照参数个数降序 if (constructorToUse != null && argsToUse.length > paramTypes.length) { // Already found greedy constructor that can be satisfied -> // do not look any further, there are only less greedy constructors left. break; } if (paramTypes.length < minNrOfArgs) { continue; } ArgumentsHolder argsHolder; // 构造函数参数从配置文件中获取的情况 if (resolvedValues != null) { // 有参数则直接根据值构造对应类型的参数 try { String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length); if (paramNames == null) { ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer(); if (pnd != null) { // 获取参数名称 paramNames = pnd.getParameterNames(candidate); } } // 根据参数名称和类型创建参数容器 argsHolder = createArgumentArray( beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring); } catch (UnsatisfiedDependencyException ex) { if (this.beanFactory.logger.isTraceEnabled()) { this.beanFactory.logger.trace( "Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex); } // Swallow and try next constructor. if (causes == null) { causes = new LinkedList<UnsatisfiedDependencyException>(); } causes.add(ex); continue; } } // 构造函数参数从getBean方法传入的情况 else { // Explicit arguments given -> arguments length must match exactly. // 对于构造函数从getBean方法传入的情况,参数数目必须精确匹配 if (paramTypes.length != explicitArgs.length) { continue; } argsHolder = new ArgumentsHolder(explicitArgs); } // 检测是否有不确定性的构造函数存在,例如不同构造函数的参数为父子关系 int typeDiffWeight = (mbd.isLenientConstructorResolution() ? argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes)); // Choose this constructor if it represents the closest match. // 选择最为接近的匹配作为构造函数 if (typeDiffWeight < minTypeDiffWeight) { constructorToUse = candidate; argsHolderToUse = argsHolder; argsToUse = argsHolder.arguments; minTypeDiffWeight = typeDiffWeight; ambiguousConstructors = null; } else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) { if (ambiguousConstructors == null) { ambiguousConstructors = new LinkedHashSet<Constructor<?>>(); ambiguousConstructors.add(constructorToUse); } ambiguousConstructors.add(candidate); } } if (constructorToUse == null) { if (causes != null) { UnsatisfiedDependencyException ex = causes.removeLast(); for (Exception cause : causes) { this.beanFactory.onSuppressedException(cause); } throw ex; } throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Could not resolve matching constructor " + "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)"); } else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Ambiguous constructor matches found in bean '" + beanName + "' " + "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " + ambiguousConstructors); } if (explicitArgs == null) { // 将解析的构造函数加入缓存 argsHolderToUse.storeCache(mbd, constructorToUse); } } // 确定了构造函数以及参数后,使用构造函数对bean进行实例化 try { Object beanInstance; if (System.getSecurityManager() != null) { final Constructor<?> ctorToUse = constructorToUse; final Object[] argumentsToUse = argsToUse; beanInstance = AccessController.doPrivileged( new PrivilegedAction<Object>() { @Override public Object run() { return beanFactory .getInstantiationStrategy() .instantiate(mbd, beanName, beanFactory, ctorToUse, argumentsToUse); } }, beanFactory.getAccessControlContext()); } else { beanInstance = this.beanFactory .getInstantiationStrategy() .instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse); } // 将构建的实例加入BeanWrapper中 bw.setWrappedInstance(beanInstance); return bw; } catch (Throwable ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Bean instantiation via constructor failed", ex); } }