日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

注解@Autowired如何自動裝配

作者:l1050188952 更新時間: 2022-09-25 編程語言

一、概念:@Autowired是spring框架2.5之后出現,用來簡化在bean當中需要定義屬性實現自動裝配的注解,夜市最常見注解之一。

二、作用位置:可以修飾在方法,參數和注解等屬性上(以下是源碼)

//可以修飾的位置包括,   構造方法,        普通方法,           參數,       
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER,
   /* 字段,*/                      /* 注解 */
 ElementType.FIELD, ElementType.ANNOTATION_TYPE})
//保留策略是在運行時
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
//聲明了依賴屬性 默認是true
    boolean required() default true;
}

從我們看到的Autowired源碼中是沒有任何關于自動裝配的代碼的,完成自動裝配的代碼是在AutowiredAnnotationBeanPostProcessor類中。

<一>找到需要裝配的元素并保存(解析Autowired)

1.進源碼可以看見,AutowiredAnnotationBeanPostProcessor實現了
MergedBeanDefinitionPostProcessor接口,重寫postProcessMergedBeanDefinition()方法,實現的注入類型的預解析。

//源碼中的預加載方法
    
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,
 Class<?> beanType, String beanName) {
        InjectionMetadata metadata 
            = this.findAutowiringMetadata(beanName, beanType, (PropertyValues)null);
        metadata.checkConfigMembers(beanDefinition);
    }

2.主要邏輯是在findAutowiringMetadata()方法。這個方法主要是找到需要自動裝配的元素,該方法會去調用buildAutowiringMetadata()方法構建元數據信息。

  // findAutowiringMetadata源碼
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
//緩存Bean的名稱
        String cacheKey = StringUtils.hasLength(beanName) ? beanName : clazz.getName();
        InjectionMetadata metadata = (InjectionMetadata)this.injectionMetadataCache.get(cacheKey);
//判斷緩存是否存在
        if (InjectionMetadata.needsRefresh(metadata, clazz)) {
            synchronized(this.injectionMetadataCache) {
                metadata = (InjectionMetadata)this.injectionMetadataCache.get(cacheKey);
                if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                    if (metadata != null) {
                        metadata.clear(pvs);
                    }
//目標Bean的元數據信息
                    metadata = this.buildAutowiringMetadata(clazz);
//存入緩存
                    this.injectionMetadataCache.put(cacheKey, metadata);
                }
            }
        }

        return metadata;
    }

3.核心邏輯在buildAutowiringMetadata()方法中

private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
        LinkedList<InjectedElement> elements = new LinkedList();
        Class targetClass = clazz;

        do {
            LinkedList<InjectedElement> currElements = new LinkedList();
         //通過反射獲取目標類中所有的字段,并遍歷每一個字段,然后通過findAutowiredAnnotation()                    方法判斷字段是否使用@Autowired和@Value修飾,
        // 如果字段被@Autowired和@Value修飾,則返回注解的相關屬性信息

            ReflectionUtils.doWithLocalFields(targetClass, (field) -> {
                AnnotationAttributes ann = this.findAutowiredAnnotation(field);
                if (ann != null) {
                    if (Modifier.isStatic(field.getModifiers())) {
                        if (this.logger.isWarnEnabled()) {
                            this.logger.warn("Autowired annotation is not supported on static fields: " + field);
                        }

                        return;
                    }
                    // 獲取到@Autowired注解的required()的值
                    boolean required = this.determineRequiredStatus(ann);
                    // 將該字段封成AutowiredFieldElement對象
                    currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement(field, required));
                }

            });
            //反射獲取目標Bean的所有方法
            ReflectionUtils.doWithLocalMethods(targetClass, (method) -> {
                Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
                if (BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                    AnnotationAttributes ann = this.findAutowiredAnnotation(bridgedMethod);
                    if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                        if (Modifier.isStatic(method.getModifiers())) {
                            if (this.logger.isWarnEnabled()) {
                                this.logger.warn("Autowired annotation is not supported on static methods: " + method);
                            }

                            return;
                        }

                        if (method.getParameterCount() == 0 && this.logger.isWarnEnabled()) {
                            this.logger.warn("Autowired annotation should only be used on methods with parameters: " + method);
                        }

                        boolean required = this.determineRequiredStatus(ann);
                        PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                        
                // 將該字段封成AutowiredMethodElement對象
                        currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement(method, required, pd));
                    }

                }
            });
            elements.addAll(0, currElements);
            targetClass = targetClass.getSuperclass();
        }

    // 循環處理父類需要自動裝配的元素
 while(targetClass != null && targetClass != Object.class);

    // 將目標類對應的所有自動注入相關的元信息封裝成InjectionMetadata,然后合并到Bean定義中
        return new InjectionMetadata(clazz, elements);
    }

buildAutowiringMetadata()方法的步驟:

1》通過反射獲取目標類中所有的字段并進行遍歷,然后通過findAutowiredAnnotation()方法判斷字段是否使用@Autowired和@Value修飾,如果字段被@Autowired和@Value修飾,則返回注解的所有屬性信息。

2》通過反射獲取目標類中所有的方法;

3》解析到字段和方法的元信息保存到List<InjectionMetadata.InjectedElement>?elements集合中,字段對應的是AutowiredFieldElement類型,方法對應的則是AutowiredMethodElement類型。

4》將目標類對應的所有自動注入相關的元信息封裝成InjectionMetadata類,返回
?

buildAutowiringMetadata()方法執行完成后,會將解析得到的自動注入相關信息保存到緩存injectionMetadataCache

4.postProcessMergedBeanDefinition()方法將需要注入的屬性信息通過checkConfigMembers()

封裝在了InjectionMetadata類中,包含了裝配和內裝配類的所有信息。

public class InjectionMetadata {
    private static final Log logger = LogFactory.getLog(InjectionMetadata.class);
    private final Class<?> targetClass;
    private final Collection<InjectionMetadata.InjectedElement> injectedElements;
    @Nullable
    private volatile Set<InjectionMetadata.InjectedElement> checkedElements;

    public InjectionMetadata(Class<?> targetClass, Collection<InjectionMetadata.InjectedElement> elements) {
        this.targetClass = targetClass;
        this.injectedElements = elements;
    }

    public void checkConfigMembers(RootBeanDefinition beanDefinition) {
        Set<InjectionMetadata.InjectedElement> checkedElements = new LinkedHashSet(this.injectedElements.size());
        Iterator var3 = this.injectedElements.iterator();

        while(var3.hasNext()) {
            InjectionMetadata.InjectedElement element = (InjectionMetadata.InjectedElement)var3.next();
            Member member = element.getMember();
            if (!beanDefinition.isExternallyManagedConfigMember(member)) {
                beanDefinition.registerExternallyManagedConfigMember(member);
                checkedElements.add(element);
                if (logger.isDebugEnabled()) {
                    logger.debug("Registered injected element on class [" + this.targetClass.getName() + "]: " + element);
                }
            }
        }

        this.checkedElements = checkedElements;
    }

?<二>自動注入屬性

AutowiredAnnotationBeanPostProcessor間接實現了InstantiationAwareBeanPostProcessor接口,所以會執行到postProcessProperties()方法實現自動注入屬性。

*postProcessProperties()方法的處理流程:


? ? ? ? 1.調用findAutowiringMetadata()方法,嘗試從緩存injectionMetadataCache中獲取對應的注入元信息,如果緩存不存在,將會執行buildAutowiringMetadata()獲取;
? ? ? ? 2.循環InjectionMetadata的injectedElements屬性,全部調用InjectionMetadata.InjectedElement.injectbean, beanName, pvs方法,通過反射方式設置屬性的值;

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()) {
        // 循環elementsToIterate, 調用InjectionMetadata.InjectedElement.inject方法,通過反射方式設置屬性的值;
        for (InjectedElement element : elementsToIterate) {
            if (logger.isTraceEnabled()) {
                logger.trace("Processing injected element of bean '" + beanName + "': " + element);
            }
            element.inject(target, beanName, pvs);
        }
    }
}

總結:以上分了兩部分去說,一是解析@Autowired方法,到反射獲取目標類的屬性和方法,到存入injectionMetadataCache中,關鍵是buildAutowiringMetadata()方法。二是自動注入屬性,還是反射的方式,取injectionMetadataCache中元信息,injectbean, beanName, pvs方法是關鍵

原文鏈接:https://blog.csdn.net/l1050188952/article/details/125959694

欄目分類
最近更新