手写spring ioc(三)

手写spring ioc(三)

前言

前面已经完成了ioc基本功能,也解决了循环依赖,现在ioc剩下的最大一块就是推断构造器,这一块比较难写,涉及到spring扩展点BeanPostProcessor, 这个扩展点可以说是艺术般的存在,不仅解耦,而且可扩展性极强,代码也清晰明了,笔者先声明一点,推断构造器笔者是模仿spring framework写的,模仿的有7,8成,几乎一模一样了,没办法,技术菜就得从模仿开始。
其实本篇挺难写的,感觉比我写源码还难,在此我先给出ioc3的源码,可以直接照着源码学习,不看本篇亦可。
ioc3源码

推断构造器

本篇不会像之前两篇给出完整代码,因为改动较大,只写关键地方
最好参照笔者另一篇博客剑指spring源码4的推断构造器,结合起来理解效果更佳

createBeanInstance

private Object  createBeanInstance(String beanName,BeanDefinition bd) throws Exception {
        //省略factoryMethod

        //推断构造器
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(bd.getBeanClass(), beanName);

        //自动装配
        if (ctors != null || bd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
                bd.hasConstructorArgumentValues()) {
            return new ConstructorResolver(this).autowireConstructor(beanName, bd, ctors);
        }
        //使用默认构造器
        return  bd.getBeanClass().newInstance();
    }

determineConstructorsFromBeanPostProcessors

private Constructor<?>[] determineConstructorsFromBeanPostProcessors(Class<?> beanClass, String beanName) {
        if (beanClass != null && hasInstantiationAwareBeanPostProcessors) {
            for (BeanPostProcessor bp : beanPostProcessors) {
                if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                    SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                    Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
                    if (ctors != null) {
                        return ctors;
                    }
                }
            }
        }
        return null;
    }

determineCandidateConstructors

@Override
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) {
        //所有的构造器
        Constructor<?>[] rawCandidates = beanClass.getDeclaredConstructors();

        //@Autowired(false)的构造器
        List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);

        //@Autowired(true)的构造器
        Constructor<?> requiredConstructor = null;

        //默认无参构造器
        Constructor<?> defaultConstructor = null;

        //最终返回的构造器
        Constructor<?>[] candidateConstructors = null;


        for (Constructor<?> candidate : rawCandidates) {
            Autowired auto = candidate.getAnnotation(Autowired.class);
            if(auto!=null){
                //取出Autowired的属性值required
                boolean required = auto.required();
                //如果是true
                if (required) {
                    //@Autowired(true)的构造器只能有一个 ,如果多个直接报错
                    if (requiredConstructor != null) {
                        throw new RuntimeException("find more than one required(true) constructor when determine "+beanName+" constructor");
                    }
                    //给requiredConstructor赋值
                    requiredConstructor = candidate;
                }
                //添加到false构造器集合
                candidates.add(candidate);
            }//给默认构造器赋值
            else if (candidate.getParameterCount() == 0) {
                defaultConstructor = candidate;
            }
        }

        // true的构造器
        if(requiredConstructor!=null){
            candidateConstructors = new Constructor<?>[] {requiredConstructor};
        }
        //false的构造器
        else if (!candidates.isEmpty()) {
            //只有Autowried(false)会出现candidates不空,而requiredConstructor为空的现象
            if (requiredConstructor == null) {
                //添加默认的
                if (defaultConstructor != null) {
                    candidates.add(defaultConstructor);
                }
            }
            candidateConstructors = candidates.toArray(new Constructor<?>[0]);
        }
        //只有一个构造器(有参),直接返回这个就行了
        else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
            candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
        }
        else {
            candidateConstructors = new Constructor<?>[0];
        }

        return (candidateConstructors.length > 0 ? candidateConstructors : null);
    }

autowireConstructor

public Object autowireConstructor(String beanName, BeanDefinition bd, Constructor<?>[] ctors) throws IllegalAccessException, InstantiationException, InvocationTargetException {
        //最终使用的构造器
        Constructor<?> constructorToUse = null;
        //最终使用的构造器的参数
        Object[] argsToUse = null;
        Constructor<?>[] candidates = ctors;

        if(null==candidates){
            candidates = bd.getBeanClass().getDeclaredConstructors();
        }

        //只有一个构造器
        if (candidates.length == 1  && !bd.hasConstructorArgumentValues()) {
            Constructor<?> uniqueCandidate = candidates[0];
            //并且是默认构造
            if (uniqueCandidate.getParameterCount() == 0) {
                return bd.getBeanClass().newInstance();
            }
        }

        //是否需要自动装配,如果有构造器或者装配模式是构造器装配都要进行自动装配
        //即springbean 会自动装配给参数

        //如果只有constructorArgumentValues,但是没有ctors,也不是构造器装配模式,autowiring=false
        //他只会找和constructorArgumentValues参数一摸一样的构造器
        boolean autowiring = (ctors != null ||
                bd.getResolvedAutowireMode() == BeanFactory.AUTOWIRE_CONSTRUCTOR);

        //最小参数个数
        int minNrOfArgs = bd.getConstructorArgumentValues()==null?0:bd.getConstructorArgumentValues().size();

        //最小类型差异权重,此值越大差异越大,初始化为最大差异
        int minTypeDiffWeight = Integer.MAX_VALUE;

        //模棱两可的构造器集合,用于存储spring都不确定的构造器集合
        Set<Constructor<?>> ambiguousConstructors = null;

        //遍历构造器
        for (Constructor<?> candidate : candidates) {
            //构造器参数类型数组
            Class<?>[] paramTypes = candidate.getParameterTypes();
            //已经有最终构造器&&已经有最终构造器参数&&最终构造器参数长度>当前构造器参数长度(直接跳出循环,使用constructorToUse)
            if (constructorToUse != null && argsToUse != null && argsToUse.length > paramTypes.length) {
                break;
            }

            //当前构造器参数长度<构造器参数的最小个数,这种情况当前构造器肯定不合格,直接抛弃当前构造器
            if (paramTypes.length < minNrOfArgs) {
                continue;
            }

            Object[] arguments = null;
            try {
                arguments = createArgumentArray(candidate,bd,autowiring);
            } catch (Exception e) {
                //若构造器参数不是@Value的&&不在spring容器就抛异常,并且跳过此构造器
                //转换异常也会抛异常
                e.printStackTrace();
                continue;
            }

            int typeDiffWeight = ClassUtils.getAssignabilityWeight(paramTypes,arguments);

            if (typeDiffWeight < minTypeDiffWeight) {
                //记录当前构造器及参数
                constructorToUse = candidate;
                argsToUse = arguments;
                //更新最小差异权重
                minTypeDiffWeight = typeDiffWeight;
                //重置ambiguousConstructors为null
                ambiguousConstructors = null;
            }
            //如果已经有了最终的构造器可供使用&&当前构造器计算出来的权重==最小差异权重
            else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
                //这下spring就为难了,他把这两个构造器加到模糊集合了
                if (ambiguousConstructors == null) {
                    ambiguousConstructors = new LinkedHashSet<>();
                    ambiguousConstructors.add(constructorToUse);
                }
                ambiguousConstructors.add(candidate);
            }
        }
        if (constructorToUse == null) {
            throw new RuntimeException(beanName+
                    "  Could not resolve matching constructor ");
        }else if (ambiguousConstructors != null && !bd.isLenientConstructorResolution()) {
            throw new RuntimeException("Ambiguous constructor matches found in bean '" + beanName + "' "+ ambiguousConstructors);
        }
        Objects.requireNonNull(argsToUse, beanName+ " Unresolved constructor arguments");

        return constructorToUse.newInstance(argsToUse);
    }

createArgumentArray

//argsToUse: 涉及@Value,@Autowired,springBean,constructorArgumentValues,autowiring
    private Object[] createArgumentArray(Constructor<?> candidate, BeanDefinition bd, boolean autowiring)throws Exception{
        //autowiring=true 自动装配,会解析@Value,@Autowired,springBean
        //autowiring=false,手动装配,不会解析@Value,@Autowired,springBean,只要解析constructorArgumentValues
        if(autowiring){
            //如果是自动注入并且还有constructorArgumentValues,以constructorArgumentValues优先
            Parameter[] params = candidate.getParameters();
            Object[] arguments = new Object[params.length];
            List<?> constructorArgumentValues = bd.getConstructorArgumentValues();

            //引入spring-core的asm技术,因为params[i].getName() 获得的参数名字是arg0 arg1
            LocalVariableTableParameterNameDiscoverer localVariableTableParameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
            String[] parameterNames = localVariableTableParameterNameDiscoverer.getParameterNames(candidate);

            for (int i=0;i<params.length;i++){
                if(params[i].isAnnotationPresent(Value.class)){
                    //拿到@Value的值
                    String value = params[i].getAnnotation(Value.class).value();

                    //基本类型转包装类型
                    Class<?>paramType = params[i].getType();
                    if(ClassUtils.primitiveTypeToWrapperMap.containsKey(paramType)){
                        paramType = ClassUtils.primitiveTypeToWrapperMap.get(paramType);
                    }
                    //如果constructorArgumentValues有此参数&&并且类型一致,优先使用constructorArgumentValues
                    if(null!=constructorArgumentValues&&
                       constructorArgumentValues.size()>i&&
                       null!=constructorArgumentValues.get(i)&&
                       paramType.isAssignableFrom(constructorArgumentValues.get(i).getClass())){
                        arguments[i] = constructorArgumentValues.get(i);
                    }else{
                        //使用@Value的值(getBaseValue防止 object to int/float/... error)
                        arguments[i] = ValueUtils.getBaseValue(params[i].getType(),value);
                    }
                }else{
                    if(null!=constructorArgumentValues&&
                            constructorArgumentValues.size()>i&&
                            null!=constructorArgumentValues.get(i)&&
                            params[i].getType().isAssignableFrom(constructorArgumentValues.get(i).getClass())){
                        arguments[i] = constructorArgumentValues.get(i);
                    }else{
                        arguments[i] = beanFactory.getBean(parameterNames[i]);
                    }
                }
            }
            return arguments;
        }
        //autowiring为false的话constructorArgumentValues必定不为null
        else{
            return bd.getConstructorArgumentValues().toArray(new Object[0]);
        }
    }

本篇博客不仅难于源代码,连测试用例笔者也是想了又想,生怕漏了情况没有测试到,在上传的文件中就有一个比较好的测试用例,另外如果有疏漏的地方欢迎大家指出,我会优化

发布了127 篇原创文章 · 获赞 68 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/LiuRenyou/article/details/103524216