1. 程式人生 > 實用技巧 >@AUTOWIRED VS @INJECT VS @RESOURCE

@AUTOWIRED VS @INJECT VS @RESOURCE

我們可以使用下面三個註釋來注入依賴項。

  • @Resource–在javax.annotation包中定義,此註釋是JSR-250註釋集合的一部分,與javaee一起打包。
  • @Inject–在javax.inject包中定義。為了訪問@inject註釋,javax.inject庫必須宣告為Maven依賴項。
  • @Autowired–在org.springframework.bean.factory包中定義,也是Spring框架的一部分。

@Autowired和@Inject註解的行為相同。這兩個註解使用AutowiredAnnotationBeanPostProcessor注入依賴關係。

@Resource使用CommonAnnotationBeanPostProcessor注入依賴項。

執行的順序

@Autowired和@Inject

    1. 按Type匹配
    2. 按Qualifiers匹配
    3. 按Name匹配

@Resource

    1. 按Name匹配
    2. 按Type匹配
    3. 按Qualifiers匹配(如果按Name找到匹配項,則忽略)

在下面的示例中,讓我們看看這些註釋是如何工作的。

這裡,我們有Animal介面和兩個實現Tiger和Lion。

Animal:

/**
 * @author:crelle
 * @className:Animal
 * @version:1.0.0
 * @date:2020/9/23
 * @description:XX
 **/
public interface Animal {

    String type();
}

Tiger:
import org.springframework.stereotype.Component;

/**
 * @author:crelle
 * @className:Tiger
 * @version:1.0.0
 * @date:2020/9/23
 * @description:XX
 **/
@Component
public class Tiger implements Animal {
    @Override
    public String type() {
        return "Tiger";
    }
}

Lion:

import org.springframework.stereotype.Component;

/** * @author:crelle * @className:Lion * @version:1.0.0 * @date:2020/9/23 * @description:XX **/ @Component public class Lion implements Animal { @Override public String type() { return "Lion"; } }

場景1:介面型別注入——使用@Resource或@Inject或@Autowired

AnimalKeeper1:

import org.springframework.beans.factory.annotation.Autowired;
import javax.inject.Inject;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @author:crelle
 * @className:AnimalKeeper
 * @version:1.0.0
 * @date:2020/9/23
 * @description: cenario 1 : Inject using Interface type – Using @Resource or @Inject or @Autowired
 **/
@Component
public class AnimalKeeper1 {


      @Resource
private Animal animal; // @Inject // private Animal animal; // // @Autowired // private Animal animal; public Animal getAnimal() { return animal; } }
import crelle.test.springframework.beans.factory.annotation.annotationtypes.test1.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

    @Autowired
    private AnimalKeeper1 animalKeeper;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {

        System.out.println(animalKeeper.getAnimal().type());

    }
}

輸出

Field animalKeeper in crelle.test.springframework.DemoApplication required a single bean, but 2 were found:
    - lion: defined in file [D:\coding\try-new-technologies\spring-framework-test\target\classes\crelle\test\springframework\beans\factory\annotation\annotationtypes\test1\Lion.class]
    - tiger: defined in file [D:\coding\try-new-technologies\spring-framework-test\target\classes\crelle\test\springframework\beans\factory\annotation\annotationtypes\test1\Tiger.class]

使用下面的註解也會給出上面的錯誤。

 @Inject
 private  Animal animal;


 @Autowired
 private  Animal animal;

所有的註解都在做同樣的事情,即嘗試按Type注入依賴項(Tiger和Lion).因此Spring容器不知道要注入Tiger或者Lion,注入失敗!

如果你確定要注入Tiger實現類,可以使用@Primary註解。

場景2:使用filed type 作為具體類進行注入:-使用@Resource或@Inject或@Autowired

AnimalKeeper2:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.inject.Inject;

/**
 * @author:crelle
 * @className:AnimalKeeper1
 * @version:1.0.0
 * @date:2020/9/23
 * @description: Scenario 2 : Inject using field type as concrete class:- Using @Resource or @Inject or @Autowired
 **/
@Component
public class AnimalKeeper2 {

//    @Resource
//    private Tiger animal;

//     @Inject
//     private Tiger animal;

     @Autowired
     private Tiger animal;


    public Tiger getAnimal() {
        return animal;
    }
}
import crelle.test.springframework.beans.factory.annotation.annotationtypes.test1.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

    @Autowired
    private AnimalKeeper2 animalKeeper;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {

        System.out.println(animalKeeper.getAnimal().type());

    }
}

輸出:

Tiger

所有的註解都得到了成功的注入。

原因-所有人都在嘗試按Type注入,而Animal的型別是具體的Tiger,所以注入沒有歧義。

場景3:使用filed name注入:-使用@Resource或@Inject或@Autowired

AnimalKeeper3:

import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @author:crelle
 * @className:AnimalKeeper2
 * @version:1.0.0
 * @date:2020/9/23
 * @description: Scenario 3 : Injecting using field name:- Using @Resource or @Inject or @Autowired
 **/
@Component
public class AnimalKeeper3 {

    @Resource
    private Animal tiger;

    // @Inject
    // private Animal tiger;

    // @Autowired
    // private Animal tiger;


    public Animal getTiger() {
        return tiger;
    }
}
import crelle.test.springframework.beans.factory.annotation.annotationtypes.test1.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

    @Autowired
    private AnimalKeeper3 animalKeeper;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {

        System.out.println(animalKeeper.getTiger().type());

    }
}

輸出:

Tiger

所有註解都將成功注入。

原因:它是按filed name注入的,每當我們在類上使用@Component時,類名本身就會自動註冊為spring bean。

Tiger類用Spring容器註冊為tiger bean,而tiger bean是容器中唯一可用的類,因此沒有歧義。

場景4:使用具有正確限定符名稱的Qualifier:-使用@Resource或@Inject或@Autowired

AnimalKeeper4:

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @author:crelle
 * @className:AnimalKeeper4
 * @version:1.0.0
 * @date:2020/9/23
 * @description: Scenario 4 : Using Qualifier with correct qualifier name:- Using @Resource or @Inject or @Autowired
 **/
@Component
public class AnimalKeeper4 {

    @Resource
    @Qualifier("tiger")
    private Animal animal;

    // @Inject
    // @Qualifier(“tiger”)
    // private Animal animal;

    // @Autowired
    // @Qualifier(“tiger”)
    // private Animal animal;


    public Animal getAnimal() {
        return animal;
    }
}
import crelle.test.springframework.beans.factory.annotation.annotationtypes.test1.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

    @Autowired
    private AnimalKeeper4 animalKeeper;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {

        System.out.println(animalKeeper.getAnimal().type());

    }
}

輸出:

Tiger

所有註解都成功地注入了依賴bean。

原因:所有這些都是通過使用限定符名稱tiger進行注入的,而容器中只有一個具有此名稱的bean。

場景5:使用限定符名稱不正確但欄位名稱正確的限定符

5.1@Resource的行為將不同於@Inject和@Autowired

使用@Resource–此處按名稱匹配優先。

AnimalKeeper5_1:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @author:crelle
 * @className:AnimalKeeper5
 * @version:1.0.0
 * @date:2020/9/23
 * @description: Scenario 5 : Using Qualifier with incorrect qualifier name , but with correct field name
 *                            Using @Resource – here Match by Name takes higher precedence.
 **/
@Component
public class AnimalKeeper5_1 {

@Resource
@Qualifier(value = "incorrect")
private Animal tiger;
public Animal getTiger() { return tiger; } 

}
import crelle.test.springframework.beans.factory.annotation.annotationtypes.test1.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

    @Autowired
    private AnimalKeeper5_1 animalKeeper;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {

        System.out.println(animalKeeper.getTiger().type());

    }
}

輸出:

Tiger

5.2 使用@Inject或@Autowired:限定符的優先順序高於欄位名。

AnimalKeeper5_2:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.inject.Inject;

/**
 * @author:crelle
 * @className:AnimalKeeper5_2
 * @version:1.0.0
 * @date:2020/9/23
 * @description: Using @Inject or @Autowired:Qualifier has higher precedence over field name.
 **/
@Component
public class AnimalKeeper5_2 {
    @Qualifier(value = "lion")
    @Autowired
    private Animal tiger;

// @Autowired
// @Qualifier(“incorrect”)
// private Animal tiger;

    public Animal getAnimal() {
        return tiger;
    }
}
import crelle.test.springframework.beans.factory.annotation.annotationtypes.test1.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

    @Autowired
    private AnimalKeeper5_2 animalKeeper;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {

        System.out.println(animalKeeper.getAnimal().type());

    }
}

輸出

Lion