19. Spring源码篇之@Bean的实例化

简介

前面介绍了@Bean标记的方法如何注册为BeanDefinition,有了 BeanDefinition 后,就能根据其中的信息实例化一个对象

在@Bean的BeanDefinition有几个比较重要的属性,一个是 factoryMethodName,一个是 factoryBeanName

factoryMethodName可以表示该Bean是一个@Bean,而factoryBeanName可以知道该Bean应该由谁来创建

其实到这基本就能猜测到@Bean如何实例化,无非是根据factoryBeanName找到对应的配置类,比如AppConfig,有了配置类后,又可以根据factoryMethodName知道对应的方法,那么调用一下就可以了

但过程还是挺复杂的,下面分析下源码

实例化@Bean源码分析

实例化过程在 AbstractAutowireCapableBeanFactory#createBeanInstance

其中有一步就是专门处理@Bean,由上面分析我们知道@Bean的Beandefinition会设置一个 factoryMethodName ,根据这个就可以判断是不是@bean

createBeanInstance

if (mbd.getFactoryMethodName() != null) {
    return instantiateUsingFactoryMethod(beanName, mbd, args);
}
protected BeanWrapper instantiateUsingFactoryMethod(
			String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
    return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}

使用ConstructorResolver去是实例化,进入分析

public BeanWrapper instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
    BeanWrapperImpl bw = new BeanWrapperImpl();
    // 设置一些类型转换器等
    this.beanFactory.initBeanWrapper(bw);

    Object factoryBean;
    Class<?> factoryClass;
    boolean isStatic;

    // 这里拿到的是配置类的名字,在加载@Bean源码分析中已经知道了,如果不是静态的方法,就会有factoryBeanName
    String factoryBeanName = mbd.getFactoryBeanName();
    if (factoryBeanName != null) {
        // 拿到配置类的Bean,这里并不是拿@Bean的Bean
        factoryBean = this.beanFactory.getBean(factoryBeanName);
        
        // 注册依赖Bean,表示@Bean依赖于配置类的Bean
        this.beanFactory.registerDependentBean(factoryBeanName, beanName);
        factoryClass = factoryBean.getClass();
        isStatic = false;
    } else {
        // 如果factoryBeanName为空,表示这个@Bean标记的方法是一个静态的方法
        factoryBean = null;
        factoryClass = mbd.getBeanClass(); //拿到的是配置类的Class
        isStatic = true;
    }

    Method factoryMethodToUse = null;
    ArgumentsHolder argsHolderToUse = null;
    Object[] argsToUse = null;

    // 省略了一些基本不走的逻辑...
    
    
    if (factoryMethodToUse == null || argsToUse == null) {
        factoryClass = ClassUtils.getUserClass(factoryClass); // 可能是jdk的代理对象,拿到真实的class

        List<Method> candidates = null;
        if (mbd.isFactoryMethodUnique) {
            if (factoryMethodToUse == null) {
                factoryMethodToUse = mbd.getResolvedFactoryMethod(); // 这里可能受其它逻辑影响,以及解析过了,就会把Method设置到factoryMethodToIntrospect属性 
            }
            if (factoryMethodToUse != null) {
                candidates = Collections.singletonList(factoryMethodToUse);
            }
        }
        
        if (candidates == null) {
            // 前面没有解析过
            candidates = new ArrayList<>();
            Method[] rawCandidates = getCandidateMethods(factoryClass, mbd); // 找出该配置类factoryClass的所有方法
            for (Method candidate : rawCandidates) {
                // 修饰类型一样,方法名一样,这里也有可能会找到多个重载
                if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
                    candidates.add(candidate);
                }
            }
        }

        // @Bean没有重载并且getBean也没有传入参数
        if (candidates.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
            Method uniqueCandidate = candidates.get(0); // 只有一个方法取出
            if (uniqueCandidate.getParameterCount() == 0) { // 该@Bean方法没有参数
                mbd.factoryMethodToIntrospect = uniqueCandidate;
                synchronized (mbd.constructorArgumentLock) {
                    mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
                    mbd.constructorArgumentsResolved = true;
                    mbd.resolvedConstructorArguments = EMPTY_ARGS;
                }
                // 大部分其实都是走这里 instantiate就是通过反射调用uniqueCandidate返回一个对象,然后设置到BeanWrapper返回
                bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
                return bw;
            }
        }

        if (candidates.size() > 1) {  
			candidates.sort(AutowireUtils.EXECUTABLE_COMPARATOR); // 找到了多个@Bean名字一样的,参数越多的排在前面
		}
		
        ConstructorArgumentValues resolvedValues = null;
        boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
        
        // 评分
        int minTypeDiffWeight = Integer.MAX_VALUE;
        
        // 模棱两可的@Bean,意思就是有多个@Bean,并且推断不出用哪个,是要抛出异常的
        Set<Method> ambiguousFactoryMethods = null;

		// minNrOfArgs 普通情况为0,如果指定了参数,那么就是参数的个数,或者BeanDefinition指定了构造方法参数值,那么就是这里面的长度
        int minNrOfArgs;
        if (explicitArgs != null) {
            minNrOfArgs = explicitArgs.length;
        }
        else {
            if (mbd.hasConstructorArgumentValues()) {
                ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
                resolvedValues = new ConstructorArgumentValues();
                minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
            }
            else {
                minNrOfArgs = 0;
            }
        }

        Deque<UnsatisfiedDependencyException> causes = null;

        for (Method candidate : candidates) {
            // 参数数量
            int parameterCount = candidate.getParameterCount();
            
            if (parameterCount >= minNrOfArgs) {
                ArgumentsHolder argsHolder;
          
                Class<?>[] paramTypes = candidate.getParameterTypes(); // 参数类型
                if (explicitArgs != null) {
                    // 这里的逻辑是显示的传入参数,例如getBean("bean",arg1,arg2) ,没有匹配上继续匹配下一个
                    if (paramTypes.length != explicitArgs.length) { 
                        continue;
                    }
                    argsHolder = new ArgumentsHolder(explicitArgs);
                }
                else {
                    try {
                        // 没有指定参数的情况下
                        String[] paramNames = null;
                        
                        // 找出参数名称,反射 & 本地变量表
                        ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer(); 
                        if (pnd != null) {
                            paramNames = pnd.getParameterNames(candidate);
                        }
                        // 根据BeanDefinition中定义的参数,以及通过name从beanFactory获取到Bean
                        // 最终组成为argsHolder ,这里面的详细过程后面文章讲
                        argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
                                paramTypes, paramNames, candidate, autowiring, candidates.size() == 1);
                    }
                    catch (UnsatisfiedDependencyException ex) {
                        if (causes == null) {
                            causes = new ArrayDeque<>(1);
                        }
                        // 记录异常,后面推断不出方法便抛出异常
                        causes.add(ex);
                        continue;
                    }
                }

                int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
                        argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
                
                if (typeDiffWeight < minTypeDiffWeight) {
                    // 如果根据当前的方法参数计算出来的评分更小些,那么应该使用该方法来创建Bean
                    factoryMethodToUse = candidate;
                    argsHolderToUse = argsHolder;
                    argsToUse = argsHolder.arguments;
                    minTypeDiffWeight = typeDiffWeight;
                    ambiguousFactoryMethods = null; // 同时也就不存在模棱两可的方法了
                }
                
                // 如果评分一样的,那么表示推断不出使用哪个方法构造Bean,最终找不出来要抛异常
                else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
                        !mbd.isLenientConstructorResolution() &&
                        paramTypes.length == factoryMethodToUse.getParameterCount() &&
                        !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
                    if (ambiguousFactoryMethods == null) {
                        ambiguousFactoryMethods = new LinkedHashSet<>();
                        ambiguousFactoryMethods.add(factoryMethodToUse);
                    }
                    ambiguousFactoryMethods.add(candidate);
                }
            }
        }


        if (factoryMethodToUse == null || argsToUse == null) {
            // 表示没有找到
            // 看有没有记录到异常,有抛出
            if (causes != null) {
                UnsatisfiedDependencyException ex = causes.removeLast();
                for (Exception cause : causes) {
                    this.beanFactory.onSuppressedException(cause);
                }
                throw ex;
            }
            List<String> argTypes = new ArrayList<>(minNrOfArgs);
            if (explicitArgs != null) {
                for (Object arg : explicitArgs) {
                    argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
                }
            }
            
            // ...省略,就是要抛异常
        }
        else if (void.class == factoryMethodToUse.getReturnType()) {
            // 返回值是void,不正常,抛出异常
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Invalid factory method '" + mbd.getFactoryMethodName() + "' on class [" +
                    factoryClass.getName() + "]: needs to have a non-void return type!");
        }
        else if (ambiguousFactoryMethods != null) {
            // 表示推断不出使用哪个方法构造Bean,抛异常
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Ambiguous factory method matches found on class [" + factoryClass.getName() + "] " +
                    "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
                    ambiguousFactoryMethods);
        }

        if (explicitArgs == null && argsHolderToUse != null) {
            // 找到了,缓存起来
            mbd.factoryMethodToIntrospect = factoryMethodToUse;
            argsHolderToUse.storeCache(mbd, factoryMethodToUse);
        }
    }
    
    // 通过反射调用uniqueCandidate返回一个对象,然后设置到BeanWrapper返回
    bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
    return bw;
}

以上便是@Bean的关键逻辑,根据修饰符以及方法名称找到对于的方法,可能因为重载方法有多个,这个时候如果制定了参数,那么直接根据指定的参数匹配方法,如果没有指定参数,那么spring会根据评分算法帮我们找出方法

至于其中的方法评分的算法,不是重点,大概就是说匹配成都越高的分越低,分越低就优先级越高,如果匹配度不高那么是要加分的,比如当前类型是值的类型的父类,加两分,当前类型是个接口加一分

关于这个算法,后面出文章讲解


欢迎关注,学习不迷路!

你可能感兴趣的:(spring,framework,spring,java)