spring 源码之 @Autowired 加在构造器上 autowireConstructor解析

spring @Autowired

@autowired可以写在变量和构造器上,注入bean,但是有的时候写在变量上会报空指针异常NPE,然后通过写在构造器上就解决了此问题,如下所示:
这种方式会报错

public class Test{
    @Autowired
    private A a;

    private final String prefix = a.getExcelPrefix();

........
}

正确、不报错

public class Test{
    private final String prefix;

    @Autowired
    public Test(A a) {
        this.prefix= a.getExcelPrefix();
    }

........
}
  • 其实这两种方式都可以使用,但报错的原因是加载顺序的问题,@autowired写在变量上的注入要等到类完全加载完,才会将相应的bean注入,而变量是在加载类的时候按照相应顺序加载的,所以变量的加载要早于@autowired变量的加载,那么给变量prefix 赋值的时候所使用的a,其实还没有被注入,所以报空指针,而使用构造器就在加载类的时候将a加载了,这样在内部使用a给prefix 赋值就完全没有问题。

  • 不使用用构造器,那么也可以不给prefix 赋值,而是在接下来的代码使用的地方,通过a.getExcelPrefix()进行赋值,这时的对a的使用是在类完全加载之后,即a被注入了,所以也是可以的。

  • @Autowired一定要等本类构造完成后,才能从外部引用设置进来。所以@Autowired的注入时间一定会晚于构造函数的执行时间。但在初始化变量的时候就使用了还没注入的bean,所以导致了NPE。如果在初始化其它变量时不使用这个要注入的bean,而是在以后的方法调用的时候去赋值,是可以使用这个bean的,因为那时类已初始化好,即已注入好了。

解析下@Autowired加在构造器上的原理。

在创建实例里的代码里会对构造器进行判断,是否需要对构造器中的参数进行解析注入。
以下是org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance
方法代码片段
在这里插入图片描述

autowireConstructor方法在AbstractAutowireCapableBeanFactory类中调用,这个方法作用是获取被包装后的bean,包装后的对象是BeanWrapper对象,这个对象的实现类是BeanWrapperImpl。其中包含被封装后待处理的bean,和设置bean属性的属性编辑器。
现在对这个方法进行分析:

  //AbstractAutowireCapableBeanFactory类中
    protected BeanWrapper autowireConstructor(
            String beanName, RootBeanDefinition mbd, Constructor<?>[] ctors, Object[] explicitArgs) {
  //此处的this就是AbstractAutowireCapableBeanFactory
        return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
    }

ConstructorResolver类中的autowireConstructor方法

 public BeanWrapper autowireConstructor(
            final String beanName, final RootBeanDefinition mbd, Constructor<?>[] chosenCtors, final Object[] explicitArgs) {
        //先实例化一个BeanWrapperImpl类对象
        BeanWrapperImpl bw = new BeanWrapperImpl();
       /*
		这里的beanFactory是初始化ConstructorResolver构造器的时候在
		AbstractAutowireCapableBeanFactory类的autowireConstructor
		方法中传进来的就是AbstractAutowireCapableBeanFactory
		 */
        //--------------------------------------------------------1--------------------------------------------//
        this.beanFactory.initBeanWrapper(bw);
        //--------------------------------------------------------1--------------------------------------------//

        Constructor<?> constructorToUse = null;
        ArgumentsHolder argsHolderToUse = null;
        Object[] argsToUse = null;
        //如果构造参数不为空就直接使用
        if (explicitArgs != null) {
            argsToUse = explicitArgs;
        }
        else {
            Object[] argsToResolve = null;
            synchronized (mbd.constructorArgumentLock) {
                //获取已缓存解析的构造函数或工厂方法
				// (resolvedConstructorOrFactoryMethod----用于缓存已解析的构造函数或工厂方法)
                constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
                //如果缓存不为空,并且构造参数已经解析缓存了,
                //(constructorArgumentsResolved为包可见,用于表示构造参数状态是否已经解析)
                if (constructorToUse != null && mbd.constructorArgumentsResolved) {
                    // Found a cached constructor...
                    //获取缓存的构造函数(resolvedConstructorArguments
                    //---用于缓存完全解析的构造函数参数的包可见字段)
                    argsToUse = mbd.resolvedConstructorArguments;
                    if (argsToUse == null) {
                        //如果获取到的缓存的构造参数是空,
                        //就获取缓存的部分准备的构造函数参数(preparedConstructorArguments
                        //---用于缓存部分准备的构造函数参数的包可见字段)
                        argsToResolve = mbd.preparedConstructorArguments;
                    }
                }
            }
            //如果缓存的参数不是空,就进行解析,解析时会对
            //argsToResolve中的每个的类型进行转化,也是一个复杂的逻辑
            if (argsToResolve != null) {
                //-----------------------------------------2---------------------------------//
                argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
                //-----------------------------------------2---------------------------------//
            }
        }
        //如果缓存的构造器不存在,就说明没有bean进行过解析,需要去关联对应的bean的构造器
        if (constructorToUse == null) {
            // Need to resolve the constructor.
            //如果传入的构造器不是空的,那么就获取bean的注入模式,
            //如果是空就按照构造器注入方式注入
            boolean autowiring = (chosenCtors != null ||
                    //getResolvedAutowireMode方法逻辑是,
                    //如果是自适应注入方法就看有没有无参构造器,
                    //如果存在就按照type类型注入,
                    //如果不存在就按照构造器方式注入,
                    //如果没有设置注入方式就不注入
                    mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
            ConstructorArgumentValues resolvedValues = null;

            int minNrOfArgs;
            //传入的构造参数不为空,这种构造器最小参数个数个传入的个数
            if (explicitArgs != null) {
                minNrOfArgs = explicitArgs.length;
            }
            else {
                //如果传的构造参数是空的,则从RootBeanDefinition中获取构造器参数,
                //并解析对应的构造参数然后添加到ConstructorArgumentValues中
                ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
                resolvedValues = new ConstructorArgumentValues();
                minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
            }

            // Take specified constructors, if any.
            Constructor<?>[] candidates = chosenCtors;
            //如果传入的构造器为空,则获取bean的Class对象,
            //然后根据bean是不是public修饰的来按照不同的方式获取所有的构造器
            if (candidates == null) {
                Class<?> beanClass = mbd.getBeanClass();
                try {
                    //getDeclaredConstructors返回所有的构造器
                    //(包括public和private修饰的),getConstructors返回public修饰的
                    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>protect>private,在同为public时构造器多的排在前面
            AutowireUtils.sortConstructors(candidates);
            int minTypeDiffWeight = Integer.MAX_VALUE;
            Set<Constructor<?>> ambiguousConstructors = null;
            List<Exception> 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;
                //没有找到合适的构造器就进行下面的步骤
                //如果ConstructorArgumentValues不为空就说明有构造参数
                if (resolvedValues != null) {
                    try {
                        String[] paramNames = null;
                        //检查给定的“java.beans.ConstructorProperties”类型的参数能否被加载,
                        //“java.beans.ConstructorProperties”是ConstructorResolver的一个静态常量,是一个Java标签的路径
                        if (constructorPropertiesAnnotationAvailable) {
                            //获取有ConstructorProperties标签的参数,因为上面有判断是否可以被加载,所这里直接能够拿到贴了标签的构造参数名称
                            //ConstructorProperties标签的作用=======》构造函数上的注释,显示该构造函数的参数如何与构造对象的getter方法相对应
                            paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
                        }
                        //如果paramNames是空,则说明参数没有被获取到,则在beanFactory中
                        //获取用于获取方法参数的ParameterNameDiscoverer对象,然后获取参数名称
                        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);
                        }
                        if (i == candidates.length - 1 && constructorToUse == null) {
                            if (causes != null) {
                                for (Exception cause : causes) {
                                    this.beanFactory.onSuppressedException(cause);
                                }
                            }
                            throw ex;
                        }
                        else {
                            // Swallow and try next constructor.
                            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);
                }
                //如果是宽松的构造策略,则对比spring构造的参数数组的类型和获取到的构造器参数的参数类型进行对比,返回不同的个数
                //如果是严格的构造策略,则检查能否将构造的参数数组赋值到构造器参数的参数列表中
                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) {
                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);
            }
        }

        try {
            Object beanInstance;
            //下面步骤都是一样的,用上面得到的构造器(无论是从bean对象中获取的还是spring自己构建的)
            //和参数来反射创建bean实例,并放到BeanWrapperImpl对象中然后返回
            if (System.getSecurityManager() != null) {
                final Constructor<?> ctorToUse = constructorToUse;
                final Object[] argumentsToUse = argsToUse;
                beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
                    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);
            }

            bw.setWrappedInstance(beanInstance);
            return bw;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
        }
    }

方法1initBeanWrapper

  //BeanWrapper继承了PropertyEditorRegistry
    protected void initBeanWrapper(BeanWrapper bw) {
        //设置类型转换的ConversionService
        bw.setConversionService(getConversionService());
        //将用户自定义的PropertyEditorRegistrar和PropertyEditor保存BeanWrapper中
        registerCustomEditors(bw);
    }

    protected void registerCustomEditors(PropertyEditorRegistry registry) {
        //获取registrySupport
        PropertyEditorRegistrySupport registrySupport =
                (registry instanceof PropertyEditorRegistrySupport ? (PropertyEditorRegistrySupport) registry : null);
        //如果registrySupport不为空,设置于配置目的的配置值编辑器(例如StringArrayPropertyEditor)为可用,默认情况下,这些编辑器不会被注册,因为它们通常不适合数据绑定
        if (registrySupport != null) {
            registrySupport.useConfigValueEditors();
        }
        //如果自定义的PropertyEditorRegistrar不为空,则需要将这些用户自定义的注册编辑器进行注册
        if (!this.propertyEditorRegistrars.isEmpty()) {
            for (PropertyEditorRegistrar registrar : this.propertyEditorRegistrars) {
                try {
                    registrar.registerCustomEditors(registry);
                }
                catch (BeanCreationException ex) {
                    Throwable rootCause = ex.getMostSpecificCause();
                    if (rootCause instanceof BeanCurrentlyInCreationException) {
                        BeanCreationException bce = (BeanCreationException) rootCause;
                        if (isCurrentlyInCreation(bce.getBeanName())) {
                            if (logger.isDebugEnabled()) {
                                logger.debug("PropertyEditorRegistrar [" + registrar.getClass().getName() +
                                        "] failed because it tried to obtain currently created bean '" +
                                        ex.getBeanName() + "': " + ex.getMessage());
                            }
                            onSuppressedException(ex);
                            continue;
                        }
                    }
                    throw ex;
                }
            }
        }
        //获取用户注册的注册器列表,如果不为空,则取出这些注册器并实例化,然后放到PropertyEditorRegistry类的用于存放用户自定义注册器的map中customEditors
        if (!this.customEditors.isEmpty()) {
            for (Map.Entry<Class<?>, Class<? extends PropertyEditor>> entry : this.customEditors.entrySet()) {
                Class<?> requiredType = entry.getKey();
                Class<? extends PropertyEditor> editorClass = entry.getValue();
                registry.registerCustomEditor(requiredType, BeanUtils.instantiateClass(editorClass));
            }
        }
    }

版权声明:本文为weixin_42213903原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。