Spring attribute filling source code analysis (simple and practical version)

1. What is attribute padding

Spring's attribute filling is mainly to complete the object attribute assignment through populateBeanthe method to gradually complete the initialization of the bean

There are only 3 ways to fill attributes

1. Fill in according to the attribute name

2. Fill according to attribute type

When does thinking come about? ? ?

It is more common in the integration of third-party frameworks and Spring. For example: Mybatis integrates with Spring. When the Mapper interface is registered as BeanDefinition, the automatic injection mode is specified as " 按类型注入"

// 代码位置:org.mybatis.spring.mapper.ClassPathMapperScanner#processBeanDefinitions方法
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);

3. The post-processor is basically considered as AutowiredAnnotationBeanPostProcessora class

It is more common in self-development . The core is to realize the dependency injection of attribute or method modification annotations such as @Value, @Autowired, and so on, or the process of finding and filling dependent objects@Resource

  • @Value, @Autowiredthe processing class is AutowiredAnnotationBeanPostProcessorprocessed
  • @Resourceis CommonAnnotationBeanPostProcessorprocessed

2. Overall process

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    
    


    boolean continueWithPropertyPopulation = true;

    // <1> 应用InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation方法
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    
    
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
    
    
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
    
    
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
    
    
                    continueWithPropertyPopulation = false;
                    break;
                }
            }
        }
    }

    if (!continueWithPropertyPopulation) {
    
    
        return;
    }

    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

    // <2> 根据名称自动注入 或者 根据类型自动注入
    if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
    
    
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
        // Add property values based on autowire by name if applicable
        // <2.1> 根据名称添加属性值
        if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
    
    
            autowireByName(beanName, mbd, bw, newPvs);
        }
        // Add property values based on autowire by type if applicable
        // <2.2> 根据类型添加属性值
        if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
    
    
            autowireByType(beanName, mbd, bw, newPvs);
        }
        pvs = newPvs;
    }

    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

    PropertyDescriptor[] filteredPds = null;
    if (hasInstAwareBpps) {
    
    
        if (pvs == null) {
    
    
            pvs = mbd.getPropertyValues();
        }
        // <3> 应用InstantiationAwareBeanPostProcessor的postProcessProperties方法
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
    
    
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
    
    
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                if (pvsToUse == null) {
    
    
                    if (filteredPds == null) {
    
    
                        filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                    }
                    pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                    if (pvsToUse == null) {
    
    
                        return;
                    }
                }
                pvs = pvsToUse;
            }
        }
    }

    // <4> 设置属性值
    if (pvs != null) {
    
    
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
}

  • <1>At the place, apply the postProcessAfterInstantiation method of InstantiationAwareBeanPostProcessor, whether to continue processing after instantiation, generally continue processing
  • <2>, automatically injected by name or type
    • <2.1>place, automatically injected according to the name (key analysis)
    • <2.2>place, automatically injected according to the type (key analysis)
  • <3>At the place, use the postProcessProperties method of InstantiationAwareBeanPostProcessor. Generally, use the application AutowiredAnnotationBeanPostProcessorto complete @Autowiredor @Valueannotate the processing
  • <4>, here the pvs variable is already the obtained value, here only need to set the value to the bw instance

3. Various types of injection

Conclusion: No matter what type of injection, the getBean method will be called at the end, the following analysis is just a brief description of how to call the getBean method step by step

3.1 Populate by name (autowireByName method)

Summary: This directly calls the getBean method, which is very simple and very good!

protected void autowireByName(
    String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
    
    
	// <1> 用内省机制查找需要注入的属性
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (String propertyName : propertyNames) {
    
    
        if (containsBean(propertyName)) {
    
    
            // <2> 既然是使用根据名称注入,那么简单了直接 getBean(String) 方法
            Object bean = getBean(propertyName);
            // <3> 添加到 pvs 中,返回后设置到
            pvs.add(propertyName, bean);
            registerDependentBean(propertyName, beanName);
        }
    }
}
  • <1>, use the introspection mechanism to find the properties that need to be injected (we focus on it)

    How to use introspection mechanism to find properties? ? ?

    protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
           
           
        Set<String> result = new TreeSet<>();
        PropertyValues pvs = mbd.getPropertyValues();
        // <1>、内省机制查找属性
        PropertyDescriptor[] pds = bw.getPropertyDescriptors();
        for (PropertyDescriptor pd : pds) {
           
           
            // <2> 并不是所有的属性都需要注入,所以要做过滤(过滤条件:要有 write 方法;不是简单属性而是我们常见的需要注入的属性;pvs 不包含)
            if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
                !BeanUtils.isSimpleProperty(pd.getPropertyType())) {
           
           
                result.add(pd.getName());
            }
        }
        return StringUtils.toStringArray(result);
    }
    

    As a result some code will come to the following method

    private CachedIntrospectionResults(Class<?> beanClass) throws BeansException {
           
           
    
        // <1> 内省机制得到 BeanInfo 对象
        this.beanInfo = getBeanInfo(beanClass);
    
        this.propertyDescriptorCache = new LinkedHashMap<>();
    
        // <2> 内省机制获取属性
        PropertyDescriptor[] pds = this.beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor pd : pds) {
           
           
            pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
            this.propertyDescriptorCache.put(pd.getName(), pd);
        }
    
        // <3> 循环处理父接口啊
        Class<?> currClass = beanClass;
        while (currClass != null && currClass != Object.class) {
           
           
            introspectInterfaces(beanClass, currClass);
            currClass = currClass.getSuperclass();
        }
    
    }
    
    • <1>At the place, use the introspection mechanism to obtain the BeanInfo information of the beanClass

      Introspection mechanism: Introspector.getBeanInfo(beanClass)

    • <2>, getting attributes will get all the attributes of the parent class

    • <3>, cycle through the parent interface, why not process the parent class, because there is no need to process, the introspection mechanism acquires attributes that already contain the attributes of the parent class

  • <2>Because it is injected by name, use the name of the attribute directly, and then call the getBean(String) method

  • <3>At the place, set the bean to pvs and return it, and let the main method call the setXxx method to set the data to the target

3.2 Fill by type (autowireByType method)

It is roughly the same as injection by name, with a few more steps (one more resolution dependency), the code is as follows:

protected void autowireByType(
    String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
    
    

    TypeConverter converter = getCustomTypeConverter();
    if (converter == null) {
    
    
        converter = bw;
    }

    Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
    // <1> 内省机制查找注入属性
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (String propertyName : propertyNames) {
    
    
        PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
        if (Object.class != pd.getPropertyType()) {
    
    
            MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
            boolean eager = !PriorityOrdered.class.isInstance(bw.getWrappedInstance());
            DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
            // <2> 解析依赖,重点方法
            Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
            if (autowiredArgument != null) {
    
    
                pvs.add(propertyName, autowiredArgument);
            }

        }
    }
}
  • <1>, use the introspection mechanism to find the unsatisfiedNonSimpleProperties method of the injected property, the same as the previous " 按名称填充(autowireByName方法)", omitted

  • <2>, focusing on analyzing and analyzing dependencies

    The resolveDependency method completes the dependency analysis, in fact, it calls the getBean method at the end! ! !

    public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
                                    @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
           
           
    
    
        // 解析依赖
        result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
    
        return result;
    }
    
    public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
                                      @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
           
           
    
        InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
        try {
           
           
    
            // <1> 如果注入的类型是 Array、List、Map 等集合类型
            Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
            if (multipleBeans != null) {
           
           
                return multipleBeans;
            }
    
            // <2> 注入的不是集合类型,但可能匹配了多个
            Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
            if (matchingBeans.isEmpty()) {
           
           
                if (isRequired(descriptor)) {
           
           
                    raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
                }
                return null;
            }
    
            if (matchingBeans.size() > 1) {
           
           
                // <2.1> 类型匹配了多个,那么就要决定使用哪一个(如在@Primary and @Priority就会出现这种情况)
                autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
    
                instanceCandidate = matchingBeans.get(autowiredBeanName);
            }
            else {
           
           
                // <2.2> 刚好匹配一个,更多的是这种情况
                Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
                autowiredBeanName = entry.getKey();
                instanceCandidate = entry.getValue();
            }
    
            if (autowiredBeanNames != null) {
           
           
                autowiredBeanNames.add(autowiredBeanName);
            }
            if (instanceCandidate instanceof Class) {
           
           
                // <3> 解析候选值,这里会调用 getBean 方法
                instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
            }
            Object result = instanceCandidate;
    
            // <4> 返回 getBean 方法结果
            return result;
        }
        finally {
           
           
            ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
        }
    }
    
    • <1>, handle the injection of collection types (such as Array, List, Map, etc.)
    • <2>At the place, a single injection is processed, but it may also match multiple. At this time, you need to consider the priority to select one (such as @Primary annotation)
    • <3>, call the getBean method to complete the actual dependency injection
    • <4>, return the injected result
    public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
        throws BeansException {
           
           
    	// 终于看到我们想要看的 getBean 方法了!
        return beanFactory.getBean(beanName);
    }
    

3.3 AutowiredAnnotationBeanPostProcessor 的 postProcessProperties 方法

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    
    
    // <1> 发现 Autowired 元数据
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    // <2> 执行实际注入
    metadata.inject(bean, beanName, pvs);
    return pvs;
}
  • <1>, look for the @Autowired metadata information in the beanClass

    private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);
    
    // <0> 只支持 @Autowired、@Value
    public AutowiredAnnotationBeanPostProcessor() {
           
           
        this.autowiredAnnotationTypes.add(Autowired.class);
        this.autowiredAnnotationTypes.add(Value.class);
    }
    
    private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
           
           
        List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
        Class<?> targetClass = clazz;
    
        do {
           
           
           final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
    
           // <1> 查找本地字段
           ReflectionUtils.doWithLocalFields(targetClass, field -> {
           
           
              // 是不是有@Autowired 或 @Value 这些注解
              AnnotationAttributes ann = findAutowiredAnnotation(field);
              if (ann != null) {
           
           
                 boolean required = determineRequiredStatus(ann);
                 currElements.add(new AutowiredFieldElement(field, required));
              }
           });
    
           // <2> 查找本地方法
           ReflectionUtils.doWithLocalMethods(targetClass, method -> {
           
           
              // 是不是有@Autowired 或 @Value 这些注解
              Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
              if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
           
           
                 return;
              }
              AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
              if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
           
           
                 boolean required = determineRequiredStatus(ann);
                 PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                 currElements.add(new AutowiredMethodElement(method, required, pd));
              }
           });
    
           // <3> 处理父类
           elements.addAll(0, currElements);
           targetClass = targetClass.getSuperclass();
        }
        while (targetClass != null && targetClass != Object.class);
    
        return new InjectionMetadata(clazz, elements);
    }
    
    • <1>At , it is processed whether the local field contains the specified annotation, and if so, it is added to the metadata
    • <2>At , it is processed whether the local method contains the specified annotation, and if it is included, it will be added to the metadata
    • <3>, the parent class is processed in a loop until all processing is completed
  • <2>According to the InjectionMetadata obtained earlier, the actual injection will be executed, and finally the getBean method will be called. The following simple code describes how to call the getBean method step by step

    public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
          
          
        Collection<InjectedElement> checkedElements = this.checkedElements;
        Collection<InjectedElement> elementsToIterate =
            (checkedElements != null ? checkedElements : this.injectedElements);
        // 循环处理每个注入元数据的注入
        if (!elementsToIterate.isEmpty()) {
          
          
            for (InjectedElement element : elementsToIterate) {
          
          
                element.inject(target, beanName, pvs);
            }
        }
    }
    
    protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
          
          
    
        // <1> 解析@Autowired 依赖
        value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
    	// <2> 反射设置字段的值
        if (value != null) {
          
          
            ReflectionUtils.makeAccessible(field);
            field.set(bean, value);
        }
    }
    
    • <1>, the dependency analysis method resolveDependency is the same as the previous " 按类型填充(autowireByType方法)", omitted

    • <2>At the place, reflection is used to set the attribute value, and the attribute is not added to pvs like autowireByName or autowireByType, and the attribute is set at the end

3.4 CommonAnnotationBeanPostProcessor processing @Resource annotations

Slightly, the process is basically the same as " AutowiredAnnotationBeanPostProcessor"

4. Attribute value setting

slightly

Portal: nanny Spring5 source code analysis

Welcome to exchange technology and work life with the author

contact author

Guess you like

Origin blog.csdn.net/yuchangyuan5237/article/details/130418416