예제 #1
0
  public static void main(String[] args) throws Exception {
    ParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();

    Method declaredMethod = HttpUtils.class.getDeclaredMethod("getClient", HttpHost.class);

    String[] names = discoverer.getParameterNames(declaredMethod);

    System.out.println(names[0]);
  }
  protected void loadArgsAsVariables() {
    // shortcut if no args need to be loaded
    if (ObjectUtils.isEmpty(args)) {
      return;
    }

    String key = toString(method);
    Method targetMethod = methodCache.get(key);
    if (targetMethod == null) {
      targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
      if (targetMethod == null) {
        targetMethod = method;
      }
      methodCache.put(key, targetMethod);
    }

    // save arguments as indexed variables
    for (int i = 0; i < args.length; i++) {
      setVariable("p" + i, args[i]);
    }

    String[] parameterNames = paramDiscoverer.getParameterNames(targetMethod);
    // save parameter names (if discovered)
    if (parameterNames != null) {
      for (int i = 0; i < parameterNames.length; i++) {
        setVariable(parameterNames[i], args[i]);
      }
    }
  }
  protected Object[] findArgs(HttpServletRequest request, Method method) {
    String[] names = paramNameDiscoverer.getParameterNames(method);
    if (names == null) {
      log.warn("Unable to lookup parameter names for method " + method);
      return null;
    }

    List<Object> args = new ArrayList<Object>();
    Class<?>[] types = method.getParameterTypes();
    for (int i = 0, count = types.length; i < count; i++) {
      args.add(findArg(request, types[i], names[i]));
    }
    return args.toArray();
  }
예제 #4
0
  /** {@inheritDoc} */
  public void validate(final Method method) {
    final String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);
    Assert.notNull(
        parameterNames,
        "Cannot get parameter names because the class file was compiled without debug information.");
    for (int i = 0; i < parameterNames.length; i++) {
      if (name.equals(parameterNames[i])) {
        position = i;
        break;
      }
    }

    Assert.isTrue(
        position >= 0, "Cannot find parameter with name [" + name + "] in " + method + ".");
  }
  /**
   * 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);
    }
  }