最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring?@Autowired注解超詳細示例

 更新時間:2022年08月16日 10:11:25   作者:飄飄~  
@Autowired注解可以用在類屬性,構(gòu)造函數(shù),setter方法和函數(shù)參數(shù)上,該注解可以準確地控制bean在何處如何自動裝配的過程。在默認情況下,該注解是類型驅(qū)動的注入

前言

說明:我們今天要分享的是依賴注入(DI)通過自動裝配的注解方式@Autowird注解方法的作用和實現(xiàn)原理以及實現(xiàn)機制。

在分享之前,我們先來回顧一下說明是依賴注入,依賴注入中手動注入和自動裝配的幾種方式,以便于提高大家對本篇文章的理解。

一、依賴注入的方式

對于spring配置一個bean時,如果需要給該bean提供一些初始化參數(shù),則需要通過依賴注入方式,所謂的依賴注入就是通過spring將bean所需要的一些參數(shù)傳遞到bean實例對象的過程(將依賴關(guān)系注入到對象中)

手動注入

①使用屬性的setter方法注入 ,這是最常用的方式:

要求:屬性注入要求Bean提供一個默認的構(gòu)造函數(shù),并為需要注入的屬性提供對應的Setter方法。Spring先調(diào)用Bean的默認構(gòu)造函數(shù)實例化Bean對象,然后通過反射的方式調(diào)用Setter方法注入屬性值。

②構(gòu)造器注入

使用方式:

第一,在類中,不用為屬性設(shè)置setter方法(但是可以有),但是需要生成該類帶參的構(gòu)造方法。

第二,在配置文件中配置該類的bean,并配置構(gòu)造器,在配置構(gòu)造器中用到了<constructor-arg>節(jié)點,該節(jié)點有四個屬性:

  • index是索引,指定注入的屬性位置,從0開始;
  • type是指該屬性所對應的類型;
  • ref 是指引用的依賴對象;
  • value 當注入的不是依賴對象,而是基本數(shù)據(jù)類型時,就用value;

自動裝配

XML方式進行自動裝配

大家可以看到用xml裝配bean是一件很繁瑣的事情,而且我們還要找到對應類型的bean才能裝配。

創(chuàng)建應用對象之間協(xié)作關(guān)系的行為稱為裝配。也就是說當一個對象的屬性是另一個對象時,實例化時,需要為這個對象屬性進行實例化,這就是裝配。

如果一個對象只通過接口來表明依賴關(guān)系,那么這種依賴就能夠在對象本身毫不知情的情況下,用不同的具體實現(xiàn)進行切換。但是這樣會存在一個問題,在傳統(tǒng)的依賴注入配置中,我們必須要明確要給屬性裝配哪一個bean的引用,一旦bean很多,就不好維護了?;谶@樣的場景,spring使用注解來進行自動裝配,解決這個問題。自動裝配就是開發(fā)人員不必知道具體要裝配哪個bean的引用,這個識別的工作會由spring來完成。

在sping框架中共有5種自動裝配 :

  • no:默認的方式是不進行自動裝配的,通過手工設(shè)置ref屬性來進行裝配bean。
  • byName:通過bean的名稱進行自動裝配,如果一個bean的property與另一bean的name相同,就進行自動裝配。
  • byType:通過參數(shù)的數(shù)據(jù)類型進行自動裝配。
  • constructor:利用構(gòu)造函數(shù)進行裝配,并且構(gòu)造函數(shù)的參數(shù)通過byType進行裝配。
  • autodetect:自動探測,如果有構(gòu)造方法,通過construct的方式自動裝配,否則使用byType的方式自動裝配。

上面所有方式的applicationContext.xml配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 使用注解前的配置 -->
    <context:annotation-config></context:annotation-config>
    <!-- 掃描 -->
    <context:component-scan base-package="com.ape.pojo"></context:component-scan>
    <!-- 手動注入 -->
    <!-- set注入 -->
    <bean id="Student" class="com.ape.pojo.Student">
        <property name="sid" value="1"></property>
        <property name="sname" value="張三"></property>
        <property name="smoney" value="100.00"></property>
        <property name="cat" ref="cat"></property>
    </bean>
    <!-- 構(gòu)造器注入construct -->
    <bean id="Student" class="com.ape.pojo.Student">
        <constructor-arg name="sid" value="1"></constructor-arg>
        <constructor-arg name="sname" value="張三"></constructor-arg>
        <constructor-arg name="smoney" value="100.00"></constructor-arg>
        <constructor-arg name="cat" ref="cat"></constructor-arg>
    </bean>
    <bean id="Student" class="com.ape.pojo.Student">
        <constructor-arg type="int" value="1"></constructor-arg>
        <constructor-arg type="java.lang.String" value="張三"></constructor-arg>
        <constructor-arg type="double" value="100.00"></constructor-arg>
        <constructor-arg type="com.ape.pojo.Cat" ref="cat"></constructor-arg>
    </bean>
    <bean id="Student" class="com.ape.pojo.Student">
        <constructor-arg index="0" value="1"></constructor-arg>
        <constructor-arg index="1" value="張三"></constructor-arg>
        <constructor-arg index="2" value="100.00"></constructor-arg>
        <constructor-arg index="3" ref="cat"></constructor-arg>
    </bean>
    <!-- 自動裝配 -->
    <!-- xml -->
    <bean id="Student" class="com.ape.pojo.Student" autowire="no">
        <property name="sid" value="1"></property>
        <property name="sname" value="張三"></property>
        <property name="smoney" value="100.00"></property>
        <property name="cat" ref="cat"></property>
    </bean>
    <bean id="Student" class="com.ape.pojo.Student" autowire="byName">
    </bean>
    <bean id="Student" class="com.ape.pojo.Student" autowire="byType">
    </bean>
    <bean id="Student" class="com.ape.pojo.Student" autowire="constructor">
    </bean>
    <bean id="Student" class="com.ape.pojo.Student" autowire="default">
    </bean>
</beans>

二、注解@Autowired的自動裝配原理

@Autowired自動裝配過程

使用@Autowired注解來自動裝配指定的bean。在使用@Autowired注解之前需要在Spring配置文件進行配置<context:annotation-config/>。

在啟動springIoC時,容器自動裝載了一個AutowiredAnnotationBeanPostProcessor后置處理器,當容器掃描到@Autowied、@Resource或@Inject時,就會在IOC容器自動查找需要的bean,并裝配給該對象的屬性。在使用@Autowired時,首先在容器中查詢對應類型的bean:

如果查詢結(jié)果剛好為一個,就將該bean裝配給@Autowired指定的數(shù)據(jù);

如果查詢的結(jié)果不止一個,那么@Autowired會根據(jù)名稱來查找;

如果上述查找的結(jié)果為空,那么會拋出異常。解決方法時,使用required=false。

實現(xiàn)原理

①首先看看spring的源代碼定義

閱讀代碼我們可以看到,Autowired注解可以應用在構(gòu)造方法,普通方法,參數(shù),字段,以及注解這五種類型的地方,它的保留策略是在運行時。在Spring源代碼當中,Autowired注解位于包org.springframework.beans.factory.annotation之中,如上圖。

②核心邏輯在buildAutowiringMetadata中

通過反射獲取該類的每一個字段和方法,并且分別用findAutowiredAnnotation方法遍歷每一個字段和方法,如果有@Autowired注解修飾,則返回注解相關(guān)屬性。最后這個方法返回的就是包含所有帶有autowire注解修飾的一個InjectionMetadata集合。

private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
        if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
            return InjectionMetadata.EMPTY;
        } else {
            List<InjectedElement> elements = new ArrayList();
            Class targetClass = clazz;
            do {
                List<InjectedElement> currElements = new ArrayList();
                ReflectionUtils.doWithLocalFields(targetClass, (field) -> {
                    MergedAnnotation<?> ann = this.findAutowiredAnnotation(field);
                    if (ann != null) {
                        if (Modifier.isStatic(field.getModifiers())) {
                            if (this.logger.isInfoEnabled()) {
                                this.logger.info("Autowired annotation is not supported on static fields: " + field);
                            }
                            return;
                        }
                        boolean required = this.determineRequiredStatus(ann);
                        currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement(field, required));
                    }
                });
                ReflectionUtils.doWithLocalMethods(targetClass, (method) -> {
                    Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
                    if (BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                        MergedAnnotation<?> ann = this.findAutowiredAnnotation(bridgedMethod);
                        if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                            if (Modifier.isStatic(method.getModifiers())) {
                                if (this.logger.isInfoEnabled()) {
                                    this.logger.info("Autowired annotation is not supported on static methods: " + method);
                                }
                                return;
                            }
                            if (method.getParameterCount() == 0 && this.logger.isInfoEnabled()) {
                                this.logger.info("Autowired annotation should only be used on methods with parameters: " + method);
                            }
                            boolean required = this.determineRequiredStatus(ann);
                            PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                            currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement(method, required, pd));
                        }
                    }
                });
                elements.addAll(0, currElements);
                targetClass = targetClass.getSuperclass();
            } while(targetClass != null && targetClass != Object.class);
            return InjectionMetadata.forElements(elements, clazz);
        }
    }

③InjectionMetadata類

這個類由兩部分組成: targetClass目標類和我們要獲得的injectedElements集合。

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

④ 實現(xiàn)注入邏輯

調(diào)用InjectionMetadata中的公共inject方法遍歷調(diào)用protect的inject方法

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
        InjectionMetadata metadata = this.findAutowiringMetadata(beanName, bean.getClass(), pvs);
        try {
            metadata.inject(bean, beanName, pvs);
            return pvs;
        } catch (BeanCreationException var6) {
            throw var6;
        } catch (Throwable var7) {
            throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", var7);
        }
    }

⑤調(diào)用InjectionMetadata中的公共inject

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
        Collection<InjectionMetadata.InjectedElement> checkedElements = this.checkedElements;
        Collection<InjectionMetadata.InjectedElement> elementsToIterate = checkedElements != null ? checkedElements : this.injectedElements;
        if (!((Collection)elementsToIterate).isEmpty()) {
            Iterator var6 = ((Collection)elementsToIterate).iterator();
            while(var6.hasNext()) {
                InjectionMetadata.InjectedElement element = (InjectionMetadata.InjectedElement)var6.next();
                element.inject(target, beanName, pvs);
            }
        }
    }

⑥遍歷調(diào)用protect的inject方法

protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs) throws Throwable {
            if (this.isField) {
                Field field = (Field)this.member;
                ReflectionUtils.makeAccessible(field);
                field.set(target, this.getResourceToInject(target, requestingBeanName));
            } else {
                if (this.checkPropertySkipping(pvs)) {
                    return;
                }
                try {
                    Method method = (Method)this.member;
                    ReflectionUtils.makeAccessible(method);
                    method.invoke(target, this.getResourceToInject(target, requestingBeanName));
                } catch (InvocationTargetException var5) {
                    throw var5.getTargetException();
                }
            }
        }

實質(zhì)就是inject也使用了反射技術(shù)并且依然是分成字段和方法去處理的。

到此這篇關(guān)于Spring @Autowired注解超詳細示例的文章就介紹到這了,更多相關(guān)Spring @Autowired 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • PageHelper在springboot中的使用方式

    PageHelper在springboot中的使用方式

    這篇文章主要介紹了PageHelper在springboot中的使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • Java實現(xiàn)廣度優(yōu)先遍歷的示例詳解

    Java實現(xiàn)廣度優(yōu)先遍歷的示例詳解

    廣度優(yōu)先遍歷:廣度優(yōu)先遍歷是連通圖的一種遍歷策略,因為它的思想是從一個頂點V0開始,輻射狀地優(yōu)先遍歷其周圍較廣的區(qū)域故得名。本文詳細介紹了Java如何實現(xiàn)廣度優(yōu)先遍歷,感興趣的小伙伴可以學習一下
    2022-02-02
  • java自加和自減運算過程

    java自加和自減運算過程

    這篇文章主要介紹了java自加和自減運算過程,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-03-03
  • 一招教你使用Java執(zhí)行g(shù)roovy腳本的兩種方式

    一招教你使用Java執(zhí)行g(shù)roovy腳本的兩種方式

    本文主要介紹了一招教你使用Java執(zhí)行g(shù)roovy腳本的兩種方式,一種是通過腳本引擎ScriptEngine提供的eval(String)方法執(zhí)行腳本內(nèi)容,一種是執(zhí)行g(shù)roovy腳本,感興趣的可以了解一下
    2023-09-09
  • 深入了解Java并發(fā)AQS的獨占鎖模式

    深入了解Java并發(fā)AQS的獨占鎖模式

    AQS是一種提供了原子式管理同步狀態(tài)、阻塞和喚醒線程功能以及隊列模型的簡單框架。一般來說,同步工具實現(xiàn)鎖的控制分為獨占鎖和共享鎖,而AQS提供了對這兩種模式的支持。本文主要來介紹一下獨占鎖模式,需要的可以參考一下
    2022-10-10
  • Java中Comparable與Comparator的區(qū)別解析

    Java中Comparable與Comparator的區(qū)別解析

    這篇文章主要介紹了Java中Comparable與Comparator的區(qū)別解析,實現(xiàn)Comparable接口,重寫compareTo方法,一般在實體類定義的時候就可以選擇實現(xiàn)該接口,提供一個默認的排序方式,供Arrays.sort和Collections.sort使用,需要的朋友可以參考下
    2024-01-01
  • Java單利模式與多線程總結(jié)歸納

    Java單利模式與多線程總結(jié)歸納

    這篇文章主要介紹了Java單利模式與多線程總結(jié)歸納 的相關(guān)資料,需要的朋友可以參考下
    2016-03-03
  • 使用eclipse打包Maven項目的實現(xiàn)步驟

    使用eclipse打包Maven項目的實現(xiàn)步驟

    本文主要介紹了使用eclipse打包Maven項目的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-03-03
  • spring boot 如何指定profile啟動

    spring boot 如何指定profile啟動

    這篇文章主要介紹了spring boot 如何指定profile啟動的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java如何通過"枚舉的枚舉"表示二級分類的業(yè)務場景

    Java如何通過"枚舉的枚舉"表示二級分類的業(yè)務場景

    這篇文章主要介紹了Java如何通過"枚舉的枚舉"表示二級分類的業(yè)務場景問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-06-06

最新評論

宁明县| 库尔勒市| 浮山县| 竹溪县| 肇源县| 翁牛特旗| 木里| 隆化县| 柳州市| 上虞市| 应用必备| 舟曲县| 江津市| 新昌县| 繁昌县| 高陵县| 曲阳县| 无棣县| 道孚县| 沙河市| 江安县| 南投市| 渑池县| 延安市| 泰和县| 那坡县| 昌都县| 洛浦县| 乌拉特中旗| 北辰区| 乌拉特前旗| 十堰市| 宁国市| 固始县| 那坡县| 友谊县| 九台市| 多伦县| 和平区| 平泉县| 平原县|