日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

javax.inject中@Inject、@Named、@Qualifier和@Provider用法

發(fā)布時間:2023/12/13 综合教程 61 生活家
生活随笔 收集整理的這篇文章主要介紹了 javax.inject中@Inject、@Named、@Qualifier和@Provider用法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

javax.inject

  包 javax.inject 指定了獲取對象的一種方法,該方法與構(gòu)造器、工廠以及服務(wù)定位器(例如 JNDI))這些傳統(tǒng)方法相比可以獲得更好的可重用性、可測試性以及可維護性。此方法的處理過程就是大家熟知的依賴注入,它對于大多數(shù)應(yīng)用是非常有價值的。

  javax.inject包里的幾個類:

在我們的程序中,很多類型依賴于其他類型。例如,一個 Stopwatch 可能依賴于一個 TimeSource。一些類型被另一個類型依賴,我們就把這些類型叫做這個類型的依賴(物)。在運行時查找一個依賴實例的過程叫做解析依賴。如果找不到依賴的實例,那我們稱該依賴為不能滿足的,并導(dǎo)致應(yīng)用運行失敗。

在不使用依賴注入時,對象的依賴解析有幾種方式。最常見的就是通過編寫直接調(diào)用構(gòu)造器的代碼完成:

       class Stopwatch {
           final TimeSource timeSource;
           Stopwatch () {
               timeSource = new TimeSource(…);
           }

           void start() { … }
           long stop() { … }
       }

如果需要更有彈性一點,那么我們可以通過工廠或服務(wù)定位器實現(xiàn):

       class Stopwatch {
           final TimeSource timeSource;
           Stopwatch () {
               timeSource = DefaultTimeSource.getInstance();
           }

           void start() { … }
           long stop() { … }
       }

在使用這些傳統(tǒng)方式進行依賴解析時,程序員必須做出適當權(quán)衡。構(gòu)造器非常簡潔,但卻有一些限制(對象生存期,對象復(fù)用)。工廠確實解耦了客戶與實現(xiàn),但卻需要樣本式的代碼。服務(wù)定位器更進一步地解耦了客戶與實現(xiàn),但卻降低了編譯時的類型安全。并且,這三個方式都不適合進行單元測試。例如,當程序員使用工廠時,該工廠的每一個產(chǎn)品都必須模擬出來,測試完后還要得記得清理:

       void testStopwatch() {
           TimeSource original = DefaultTimeSource.getInstance();
           DefaultTimeSource.setInstance(new MockTimeSource());
           try {
               // Now, we can actually test Stopwatch.
               Stopwatch sw = new Stopwatch();
               //…
           } finally {
               DefaultTimeSource.setInstance(original);
           }
       }

現(xiàn)實中,要模擬工廠將導(dǎo)致更多的樣本式代碼。測試模擬出的產(chǎn)品并清理它們在依賴多的情況下很快就控制不了了。更糟的是,程序員必須精確地預(yù)測未來到底需要多少這樣的彈性,并為他做的“彈性選擇”負責。如果程序員開始時選擇了構(gòu)造器方式,但后來需要一個更有彈性的方式,那他就不得不替換所有調(diào)用構(gòu)造器的代碼。如果程序員一開始過于謹慎地選擇了工廠方式,結(jié)果可能導(dǎo)致要編寫很多額外的樣本式代碼,引入了不必要的復(fù)雜度,潛在的問題比比皆是。

依賴注入就是為了解決這些問題。代替程序員調(diào)用構(gòu)造器或工廠,一個稱作依賴注入器的工具將把依賴傳遞給對象:

       class Stopwatch {
           final TimeSource timeSource;
           @Inject Stopwatch(TimeSource timeSource) {
               this.TimeSource = timeSource;
           }
           void start() { … }
           long stop() { … }
       }

注入器將更進一步地傳遞依賴給其他的依賴,直到它構(gòu)造出整個對象圖。例如,假設(shè)一個程序員需要注入器創(chuàng)建一個StopwatchWidget 實例:

 /** GUI for a Stopwatch */
    class StopwatchWidget {

        @Inject StopwatchWidget(Stopwatch sw) { … }

        …

    }

注入器可能會:

查找一個 TimeSource 實例

使用找到的 TimeSource 實例構(gòu)造一個 Stopwatch

使用構(gòu)造的 Stopwatch 實例構(gòu)造一個 StopwatchWidget

這使得代碼保持干凈,使得程序員感到使用依賴(物)的基礎(chǔ)設(shè)施非常容易。

現(xiàn)在,在單元測試中,程序員可以直接構(gòu)造對象(不使用注入器)并將該對象以模擬依賴的方式直接傳入待測對象的構(gòu)造中。程序員再也不需要為每一次測試都配置并清理工廠或服務(wù)定位器。這大大簡化了我們的單元測試:

   void testStopwatch() {
           Stopwatch sw = new Stopwatch(new MockTimeSource());
           //…
       }

完全降低了單元測試的復(fù)雜度,降低的復(fù)雜程度與待測對象的數(shù)目及其依賴成正比。

包 javax.inject 為使用這樣的輕便類提供了依賴注入注解,但沒有引入依賴配置方式。依賴配置方式取決于注入器的實現(xiàn)。程序員只需要標注了構(gòu)造器、方法或字段來說明它們的可注入性(上面的例子就是構(gòu)造器注入)。依賴注入器通過這些注解來識別一個類的依賴,并在運行時注入這些依賴。此外,注入器要能夠在構(gòu)建時驗證所有的依賴是否滿足。相比之下,服務(wù)定位器在構(gòu)建時是不能檢測到依賴不滿足情況的,直到運行時才能發(fā)現(xiàn)。

注入器實現(xiàn)有很多形式。一個注入器可以通過 XML、注解、DSL(領(lǐng)域規(guī)約語言),或是普通 Java代碼來進行配置。注入器實現(xiàn)可以使用反射或代碼生成。使用編譯時代碼生成的注入器甚至可能沒有它自己的運行時描述。而其他注入器實現(xiàn)無論在編譯時還是運行時可能都不使用代碼生成。一個“容器”,其實可以把它定義為一個注入器,不過包 javax.inject不涉及非常大概念,旨在最小化注入器實現(xiàn)的限制。

@Inject支持構(gòu)造函數(shù)、方法和字段注解,也可能使用于靜態(tài)實例成員。可注解成員可以是任意修飾符(private,package-private,protected,public)。注入順序:構(gòu)造函數(shù)、字段,然后是方法。父類的字段和方法注入優(yōu)先于子類的字段和方法,同一類中的字段和方法是沒有順序的。

@Inject注解的構(gòu)造函數(shù)可以是無參或多個參數(shù)的構(gòu)造函數(shù)。@Inject每個類中最多注解一個構(gòu)造函數(shù)。

在字段注解:

用@Inject注解
字段不能是final的
擁有一個合法的名稱
在方法上注解:

用@Inject注解
不能是抽象方法
不能聲明自身參數(shù)類型
可以有返回結(jié)果
擁有一個合法的名稱
可以有0個或多個參數(shù)
@Inject MethodModirers ResultType Identifier(FormalParameterList ) Throws MethodBody

[上述翻譯:inject的doc文檔,翻譯不好敬請諒解]

構(gòu)造函數(shù)注解:

@Inject
public House(Person owner) {
System.out.println("---這是房屋構(gòu)造函數(shù)---");
this.owner = owner;
}
字段注解:
@Inject private Person owner;
方法注解:
@Inject
public void setOwner(Person owner) {
this.owner = owner;
}
@Inject注解和Spring的@Autoware注解都是根據(jù)類型對其進行自動裝配。
SpringUtil類:

public class SpringUtil {
private static ApplicationContext context = null;
public static ApplicationContext getApplicationContext() {
if (context == null) {
context = new ClassPathXmlApplicationContext("spring.xml");
}
return context;
}

public static ApplicationContext getApplicationContext(String path) {
return new ClassPathXmlApplicationContext(path);
}

public static ApplicationContext getAnnotationConfigApplicationContext(String basePackages) {
return new AnnotationConfigApplicationContext(basePackages);
}
}
Person類:
import javax.inject.Named;

@Named
public class Person {
private String name;

public Person() {
System.out.println("---這是人的構(gòu)造函數(shù)---");
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}
House類:
@Named
public class House {
@Inject private Person owner;
public House() {
System.out.println("---這是房屋構(gòu)造函數(shù)---");
}

public Person getOwner() {
return owner;
}

public void setOwner(Person owner) {
this.owner = owner;
}
}
測試類:
public class Test {
public static void main(String[] args) {
ApplicationContext context = SpringUtil.getApplicationContext(
"test/spring/inject/bean-inject.xml");
House house = (House)context.getBean("house");
Person p = house.getOwner();
p.setName("張三");
System.out.println(house.getOwner().getName());
}
}
輸出結(jié)果:
---這是房屋構(gòu)造函數(shù)---
---這是人的構(gòu)造函數(shù)---
張三

上述例子在Spring3.1下測試成功,在Spring3.1下,每個構(gòu)造函數(shù)只初始化一次及默認的單例形式,個人感覺如果脫離Spring環(huán)境應(yīng)該每次用都會實例化新的對象,當然根據(jù)實現(xiàn)的jar包不同而不同,要不javax.inject下的@Singleton注解就沒有什么用途了。

@Named

@Named和Spring的@Component功能相同。@Named可以有值,如果沒有值生成的Bean名稱默認和類名相同。

例如:

@Named public class Person
該bean的名稱就是person。
@Named("p") public class Person
如果指定名稱,那么就是指定的名稱嘍。
@Qualifier

任何人都可以定義一個新的修飾語,一個qualifier注解應(yīng)該滿足如下條件:

定義的注解類有@Qualifier,@Retention(RUNTIME)和@Documented。
可以有屬性
可以是公共API的一部分
可以用@Target注解限定使用范圍
下面是Qualifier的例子:

Genre注解類:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
@Target(value = {ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
public @interface Genre {
User user() default User.STUDENT;
public enum User {STUDENT, TEACHER}
}
用戶接口:(對個數(shù)進行統(tǒng)計)
public interface IUserDAO {
int count();
}
StudentDAO:
@Named
@Genre(user = User.STUDENT)
public class StudentDAO implements IUserDAO{
@Override
public int count() {
System.out.println("----StudentDAO----");
return 0;
}

}
TeacherDAO:
@Named
@Genre(user = User.TEACHER)
public class TeacherDAO implements IUserDAO {

@Override
public int count() {
System.out.println("--TeacherDAO--");
return 0;
}
}
UserDAOProcessor:
@Named
public class UserDAOProcessor {
/*對TeacherDAO類的注入,如果對StudentDAO類注入應(yīng)該是:@Genre(user = User.STUDENT)或@Genre,因為@Genre默認的是STUDENT*/
@Inject
private @Genre(user = User.TEACHER) IUserDAO userDAO;

public int count() {
return userDAO.count();
}

public IUserDAO getUserDAO() {
return userDAO;
}

public void setUserDAO(IUserDAO userDAO) {
this.userDAO = userDAO;
}
}

測試類:

public class Test {
public static void main(String[] args) {
ApplicationContext context = SpringUtil.getApplicationContext(
"test/spring/inject/bean-inject.xml");
UserDAOProcessor processor = (UserDAOProcessor)context.getBean("userDAOProcessor");
System.out.println(processor.count());
}
}
輸出結(jié)果:
--TeacherDAO--
0

個人對@Qualifier的理解:

和Spring的@Qualifier大致相同
單獨用@Inject無法滿足對接口的注入,無法找到哪個具體類,所以用@Qualifier來確定注入的具體類
用到@Qualifier的注解中可以有值、無值和用枚舉類型
@Singleton

使用該注解標記該類只創(chuàng)建一次,不能被繼承。一般在類上用該注解。

總結(jié)

以上是生活随笔為你收集整理的javax.inject中@Inject、@Named、@Qualifier和@Provider用法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。