The introduction of

Simply review the following before Spring inference construction method, and the Spring by calling the post processor determineCandidateConstructors method will all be@AutowiredThe annotation's constructor is found. If it exists, Spring calls the autowireConstructor method to create the object.@AutowiredAnnotations can be interpreted as auto-injected, so it makes sense to use the autowireConstructor method to create objects. However, there are three other ways to use this method to create objects. Namely AutowireMode AUTOWIRE_CONSTRUCTOR, the second is the programmer provides ConstructorArgumentValues, this kind of circumstance Spring also can use this method to create objects, and the third is getBean provides the parameters of the situation, In each of these cases, Spring uses the autowireConstructor method to create the object. In this method, Spring also deduces the constructor once. As you can imagine, in the first case there are multiple constructors. The rest of the way, again, Spring can't immediately figure out which constructor to use, so it makes sense to have to make an inference. Let's take the method through step by stepCopy the code

AutowireConstructor method step parsing

  • A code
BeanWrapperImpl bw = new BeanWrapperImpl(); this.beanFactory.initBeanWrapper(bw); Constructor<? > constructorToUse = null; ArgumentsHolder argsHolderToUse = null; Object[] argsToUse = null; Analysis: After Spring has created a bean object, it will put the bean object into BeanWrapper, as explained in the previous article. The bean object and its corresponding Class object can then be retrieved using the get method. Since there may be multiple constructors when entering the autowireConstructor method, Spring needs to infer which constructor to use. ConstructorToUse is the variable that holds the constructors that are actually used to create the bean. Spring loops through the constructors through a for loop, and each time it finds a more suitable constructor, Will overwrite the value of this variable argsToUse used to store really used to create the object parameters, it can be us the incoming parameters, it is possible that we parse out the parameter, when deduced from Spring to a constructor, can be in ConstructorArgumentValues, ArgsHolderToUse is used to store the parameters used to create the object. If not, argsHolderToUse is used to store the parameters used to create the object. ArgsToUse = argsHolderToUse argsToUse = argsHolderToUse argsToUse = argsHolderToUse argsToUse = argsHolderToUse argsToUse = argsHolderToUse argsToUse = argsHolderToUse argsToUse = argsHolderToUse argsToUse = argsHolderToUse argsToUse = argsHolderToUse Unlike argsToUse, other forms of arguments are stored in holder. For example, Mybatis can be used to process MapperScan. It sets the BeanClass in the BeanDefinition of the scanned interface to the class object of the mapperFactoryBean, And use getConstructorArgumentValues (.) addGenericArgumentValue method adds a structural parameters: Definition. GetBeanClassName (), the parameter is of type string, said scan out the fully qualified Class name of the interface, it is important to note that mapperFactoryBean constructor is a Class object, in other words, Spring uses a converter to convert a fully qualified Class name into a Class object when creating object parsing arguments. ArgsHolderToUse stores both the original and converted arguments.Copy the code
  • Code 2
if(explicitArgs ! =null) {
  argsToUse = explicitArgs;
}
else {
  Object[] argsToResolve = null;
  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) {
    argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true); }} analysis: ExplicitArgs is the argument passed in to getBean. Spring thinks that if we call getBean and pass in the argument, the programmer wants to use the argument as a constructor argument, so Spring assigns the argument to argsToUse. In this case, Spring does not want to read the arguments and constructors inferred from the previous object creation from the cache, because there is no guarantee that the next time a programmer will use these arguments in theelseIn this statement, Spring reads the previously stored constructor and parameter (if the object has been created before) from the cache. We don't need to look at this code, because we can see what Spring puts in the cache and where. The purpose of this step is to read data from the cache if it is allowed to read from the cacheCopy the code
  • Code 3
if (constructorToUse == null || argsToUse == null) {... } bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));returnbw; Analysis: After the previous flow, Spring has defined the basic parameters and has no information about constructors and construction parameters from the cache. At this point, Spring is ready to infer constructors and parameters. You can see that as long as constructorToUse and argsToUse have anull, will begin to infer the constructor, i.eifThat's what's in there to infer constructors and parameters when thisifAfter that, Spring will call Instantiate to reflect the object and set it to BeanWrapper, which will be returnedCopy the code

The next step is to analyze the code inside the if judgment

  • Code four
Constructor<? >[] candidates = chosenCtors;if (candidates == null) { Class<? > beanClass = mbd.getBeanClass(); candidates = (mbd.isNonPublicAccessAllowed() ? beanClass.getDeclaredConstructors() : beanClass.getConstructors()); } Analysis: Found if Spring passes in an array of constructors when the autowiredConstructor method is called@AutowiredIf not, it is the last three of four cases, in which case the constructor is allowed to access notpublic, Spring gets all the constructors, otherwise it just gets thempublicIsNonPublicAccessAllowed The default value istrueIs allowed to access nonpublicMethods, this property can be beanDefinition setNonPublicAccessAllowed method to manuallyCopy the code
  • The code for five
Now that Spring has the constructor, it's time to decide which method to use, i.eforLoop through all constructors, but before doing so, Spring makes a judgment that can speed up the execution of the autowiredContructor method to some extent:if (candidates.length == 1 && explicitArgs == null&&! mbd.hasConstructorArgumentValues()) { Constructor<? > uniqueCandidate = candidates[0];
  if (uniqueCandidate.getParameterCount() == 0) {
    synchronized (mbd.constructorArgumentLock) {
      mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
      mbd.constructorArgumentsResolved = true;
      mbd.resolvedConstructorArguments = EMPTY_ARGS;
    }
    bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
    returnbw; }} analysis: if there is only one constructor, and the programmer does not voluntarily provide arguments, and the arguments to the constructor are0A word that after Must be calling the default constructor, the Spring is no longer used to determine exactly which constructor, but directly using the default constructed the object method created, at the same time the constructors and parameter information stored in the cache, so that, when called again after can be read from the cache to take priority, Note that Spring will only do that in explicitArgs fornullThe constructor and parameter information are cached only when the constructor and parameter information are cached.Copy the code
  • Code six
booleanautowiring = (chosenCtors ! =null ||
    mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
ConstructorArgumentValues resolvedValues = null;

int minNrOfArgs;
if(explicitArgs ! =null) {
  minNrOfArgs = explicitArgs.length;
}
else {
  ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
  resolvedValues = newConstructorArgumentValues(); minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); } Analysis: Autowiring indicates whether it is auto-injected while we exist@AutowiredAutowiredConstructor () {}} This parameter is not used in the autowiredConstructor method, but is used in the constructor method@AutowiredThe annotation annotation constructor or just one parameter constructor, chosenCtors, is notnullSpring calls the getBean method to retrieve parameters from the container only for automatic injection. For instance, Spring calls the getBean method to retrieve parameters from the container. We'll talk a little bit more about this argument later when it comes to taking arguments. If the programmer, when calling the getBean method, actively passes in arguments, explicitArgs is not empty, then Spring will use those arguments to find the corresponding constructor, and a class can have many constructors, If three arguments are passed in, the constructor with fewer than three arguments can be skipped. This is what minNrOfArgs does. Then the Spring will be the number of parameters will be obtained from ConstructorArgumentValues, bringing the number assigned to minNrOfArgs resolveConstructorArguments method to do the two things. The first thing to do is to place the parameters of the beanDefinition in the newly created resolvedValues. These two are identical class instances. Spring creates a new one and stores the parameters stored in the old object in the new object. Because of beanDefinition ConstructorArgumentValues not parse the parameters, and can see in resolveConstructorArguments method, Spring defines parameters such as RuntimeBeanReference, BeanDefinitionHolder, BeanDefinition... Etc. Types of cases, will be carried out in certain parsing, and ConstructorArgumentValues in beanDefinition is not do this action, the second thing is mentioned above, According to the number of the parameters of the ConstructorArgumentValues determine minNrOfArgs value to summarize: What the above code does is determine the value of minNrOfArgs, which is the number of arguments provided by the program if the programmer provided them either way, or if not0, the second for ConstructorArgumentValues parameters in parsingCopy the code
  • The code for seven
AutowireUtils.sortConstructors(candidates);
intminTypeDiffWeight = Integer.MAX_VALUE; Set<Constructor<? >> ambiguousConstructors =null; Analysis: Spring sorts constructors regularly, for examplepublic - protected - default - privateSort permissions. If the number of parameters has the same permissions, sort the number of parameters first. The reason for sorting is because Spring thinks thatpublicMethod first, if foundpublicMethod to create an object, then no other methods are considered, and Spring thinks that arguments are preferred. Perhaps Spring thinks it should make full use of arguments to create objects? For example, if the programmer provides four parameters, it cannot be created using the default constructor. The minTypeDiffWeight parameter is interesting. It represents the difference between the required and found parameters of the constructor. Spring takes the constructor with the smallest difference to create the object. For example, there are two constructors, both of which have only one parameter. The first constructor takes A class A instance, the second constructor takes A class B instance, and when traversed, the found argument takes A class A instance. Spring also uses the first constructor to create ambiguousConstructors. When the two constructors compute the same difference, Spring considers it ambiguous and does not know which constructor to use to create the object. The two constructors will be placed in the ambiguousConstructors Set. If it is ambiguousConstructors, Spring will use the first one found, if it is ambiguousConstructors, if it is ambiguousConstructors, SPring will throw an error, a bean in loose or strict by beanDefinition. SetLenientConstructorResolution methods to set and judgment of the two patterns after we will talk aboutCopy the code
  • Simple summary
In doing this, Spring does several things: <1> Fetch the constructor and parameters from the cache. If you get them, create them from the cache. If you don't get them, start inferring the constructor. <3> If there is only one default constructor, this method is called directly to complete object creation (a shortcut to object creation). <4> Determine the minimum parameters required by the constructor based on the parameters provided by the programmer. Number greater than or equal to the selected parameters minNrOfArgs value constructor, if in certain cases, the Spring will also ConstructorArgumentValues analyzes the parameters, if the program does not provide a parameter, Spring sorts the constructors according to certain rules, initializes the differential value variable to the maximum value of Integer, and defines ambiguousConstructors as the Set to store ambiguousConstructors. At this point, Now that Spring has done the work of inferring the constructor, Spring starts iterating through the constructors and taking the parameters to determine the most appropriate constructor based on the differencesCopy the code
  • Code of the eight
for(Constructor<? > candidate : candidates) { ....... To determine the most appropriate constructor, take the constructor argument....... }if (constructorToUse == null) {
  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); } analysis: through aforThe loop determines constructorToUse and argsToUse, and raises an error if no constructor is found. If an ambiguous constructor is found, but the bean is in a strict state, an error is also thrown. Spring has already found the appropriate constructor and parameters. If the programmer does not explicitly provide the parameters, but uses the parameters specified by Spring, Spring caches the constructor and parameters. Under certain conditions, Spring can fetch the corresponding data from the cacheforThe cycle is analyzedCopy the code

For loop content analysis begins

  • Code of nine
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; }} If the number of arguments in the constructor is greater than the number of arguments in the constructor, Spring considers that it has found the appropriate constructorbreakIf the number of arguments in the constructor of this loop is less than the minimum number of arguments, the next loop is enteredCopy the code
  • Code 10
ArgumentsHolder argsHolder;
if(resolvedValues ! =null) {
  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,
      getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
}
else {
  // Explicit arguments given -> arguments length must match exactly.
  if(paramTypes.length ! = explicitArgs.length) {continue;
  }
  argsHolder = newArgumentsHolder(explicitArgs); } resolvedValues is not set tonull, where explicitArgs isnull, as can be seen in the previous code if explicitArgs is notnull, Spring does not assign to resolvedValues, in other words, thisif-elseSpring calls the createArgumentArray method to create an array of parameter objects. Spring calls the createArgumentArray method to create an array of parameter objects. This is our so-called parameters above, in this method, the Spring will first take, from ConstructorArgumentValues if didn't get to say is automatic injection, Spring will use getBean method from the container, it is not fine talked about, If I have time later, I can write a separate article about this method. There are a few things going on in this method. For example, there is a code that uses the previous Autowiring method: valueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, paramName, usedValueHolders);if (valueHolder == null&& (! autowiring || paramTypes.length == resolvedValues.getArgumentCount())) { valueHolder = resolvedValues.getGenericArgumentValue(null.null, usedValueHolders); } Spring uses resolvedValues to retrieve index and generic parameters (resolvedValues and resolvedValues). If not, Spring will take it again without automatic injection (only if the programmer manually provides the parameters). The reason is that we may pass in a string, but it can be parsed into a Class object (MapperScan source code has this scenario). So this step is to get these unconverted parametersCopy the code
  • The code.
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 = newLinkedHashSet<>(); ambiguousConstructors.add(constructorToUse); } ambiguousConstructors.add(candidate); } analysis: Spring passes the previous analysisforThe loop gets the constructor, gets the argument from code ten, and Spring calculates the difference between the argument and the constructor. If the difference is smaller than the previous difference, then the constructor for this loop is the more appropriate constructor. ConstructorToUse, argsHolderToUse, argsToUse are assigned, and minTypeDiffWeight is updated, so ambiguousConstructors is also set tonullBecause suppose there is5If the difference values calculated by the first two constructors are the same, it will be placed in ambiguousConstructors, i.eelse ifWhen the third constructor is looped through, the calculated difference is smaller, indicating that the third constructor is more appropriate, and there is no need for the previous ambiguous constructor because Spring will not look for the first two constructors and reassign for the later ambiguous constructorCopy the code

At this point, the entire autowiredContructor method has been analyzed