淺談 IoC / DI

1.背景

剛開始接觸 spring 著蟹,一定不會(huì)少看到 IoC煞肾、DI 這兩個(gè)單詞命贴。

先把 spring 撇開道宅,單獨(dú)看看 IoC 和 DI 是什么意思呢?

找兩個(gè)定義:

  • IoC胸蛛,全稱 Inverse of Control污茵,控制反轉(zhuǎn)。是指葬项,由容器/第三方系統(tǒng)(例如 spring )來控制業(yè)務(wù)對(duì)象之間的依賴關(guān)系泞当,而不是像傳統(tǒng)方式中由代碼來直接控制。

  • DI民珍,全稱 Dependency Injection零蓉,依賴注入。是指穷缤,自身對(duì)象中的內(nèi)置對(duì)象是通過注入的方式進(jìn)行創(chuàng)建。

呃箩兽,看完了津肛,似懂非懂。汗贫。身坐。

2.舉個(gè)“吃飯”的例子

場(chǎng)景:在沙縣小吃/學(xué)校食堂吃飯。

沙縣小吃:

  1. 顧客到店:老板落包,我要一份炒米線部蛇。
  2. 老板:好嘞,這就給你做咐蝇。

學(xué)校食堂:

  1. 學(xué)生到食堂:阿姨涯鲁,我要這個(gè)西紅柿炒蛋,加4兩米飯有序。
  2. 食堂阿姨:好嘞抹腿,這就給你裝盤。

區(qū)別在哪呢旭寿?

  • “沙縣小吃”是由顧客到店后主動(dòng)要求“我要吃什么”警绩,然后餐館才去 new 一個(gè)你要吃的菜。
  • “學(xué)校食堂”是由食堂提前 new 很多可以提供給顧客吃的菜盅称,顧客來了之后直接挑選裝盤就可以了肩祥。

3.再舉個(gè)例子

場(chǎng)景:接口參數(shù)檢查

假設(shè)后室,我們的后臺(tái)服務(wù)拆兩個(gè)類:MyService 和 Validator 。很明顯混狠,MyService 依賴 Validator岸霹。

考慮一下, 最簡(jiǎn)單的實(shí)現(xiàn)方式是什么呢檀蹋?

3.1 傳統(tǒng)實(shí)現(xiàn)松申,new

簡(jiǎn)單介紹一下用到的類和接口:

  • IValidate.java,接口定義了 validate() 方法俯逾,對(duì)一個(gè) String 類型參數(shù)做檢查贸桶。
  • NotnullValidator.java 實(shí)現(xiàn)了 IValidate 接口的validate()方法,要求參數(shù)不能為空桌肴。
  • MyService.java皇筛,定義了一個(gè)Serve() 方法,用來接收外部參數(shù)坠七,然后對(duì)參數(shù)做非空檢查水醋。
  • Client.java,模擬調(diào)用方彪置,請(qǐng)求MyService拄踪。

代碼示例:

// IValidator.java
interface IValidator.java {
    public void validate(String param);
}

// NotnullValidator.java
class NotnullValidator implements IValidator{
    @Override
    public void validate(String param){
        System.out.println(this.getClass().getSimpleName()+ " validating param {"+param+"}");
        if(null == param || 0 == param.length()){
            System.out.println(this.getClass().getSimpleName() + " param can not be null or empty");
        }
    }
}

// MyService.java
class MyService.java {
    void Serve(String param){
        System.out.println(this.getClass().getSimpleName() + " param = " + param);
        NotnullValidator notnullValidator = new NotnullValidator();
        notnullValidator.validate(param);
    }
}

// Client.java
public class Client {
    public static void main(String[] args){
        MyService myService = new MyService();
        myService.Serve("");
        myService.Serve("123");
        /**
         * 這樣做的弊端是,依賴隱藏在函數(shù)內(nèi)部拳魁,模塊化惶桐、可用性、擴(kuò)展性潘懊、易測(cè)性都不好姚糊。
         */
    }
}

在這個(gè)例子中,MyService 直接在 Serve() 方法內(nèi)部 new 了一個(gè) NotNullValidator 實(shí)例授舟,進(jìn)行參數(shù)檢查救恨。

這樣做的問題在于:

  1. 擴(kuò)展性差,如果需要其他校驗(yàn)器释树,就要在 MyService 內(nèi)部做大調(diào)整了肠槽。
  2. 依賴管理困難,IValidator 實(shí)例的生命周期在 MyService 之內(nèi)奢啥,無法管理署浩。
  3. 可測(cè)性差,耦合太嚴(yán)重扫尺,依賴和行為完全堆到一起去了筋栋,沒法做單元測(cè)試。

那么正驻,有什么解決方法呢弊攘?
很簡(jiǎn)單抢腐,把 new NotNullValidator 這個(gè)操作拿出來就可以了。

3.2 構(gòu)造子注入

同樣的例子襟交,我們可以在 MyService 內(nèi)部定義一個(gè) IValidator 成員變量迈倍,然后再 定義一個(gè) MyService 的帶參構(gòu)造函數(shù)。

代碼示例:

// IValidator.java
interface IValidator {
    public void validate(String param);
}

// NotnullValidator.java
class NotnullValidator implements IValidator{
    @Override
    public void validate(String param){
        System.out.println(this.getClass().getSimpleName()+ " validating param {"+param+"}");
        if(null == param || 0 == param.length()){
            System.out.println(this.getClass().getSimpleName() + " param can not be null or empty");
        }
    }
}

// MyService.java
class MyService {
    private IValidator validator;

    MyService(IValidator validator) {
        System.out.println("構(gòu)造子注入");
        this.validator = validator;
    }

    void Serve(String param){
        System.out.println(this.getClass().getSimpleName() + " param = " + param);
        validator.validate(param);
    }
}

// Client.java
public class Client {
    public static void main(String[] args){
        NotnullValidator notnullValidator = new NotnullValidator();
        MyService myService = new MyService(notnullValidator);
        myService.Serve("");
        myService.Serve("123");
        /**
         * 依賴由外部管理捣域,可測(cè)性變強(qiáng)了啼染。
         * 這其實(shí)就是一種依賴注入方法。
         * 通過構(gòu)造方法注入依賴焕梅,叫做"構(gòu)造子注入"迹鹅。
         */
    }
}

在這里,Client 自己 new 了一個(gè) NotNullValidator 實(shí)例贞言,通過構(gòu)造方法傳給新的 MyService 實(shí)例斜棚。

這樣,類與類之間的依賴關(guān)系由外部管理该窗,可測(cè)試性弟蚀、可復(fù)用性都得到了很大的提升。

從應(yīng)用程序的角度描述酗失,依賴關(guān)系不再是 MyService 正向獲得一個(gè) IValidator 實(shí)現(xiàn)的實(shí)例义钉,而是 Client 先實(shí)例化一個(gè)自己想要的 IValidator 實(shí)現(xiàn),然后注入到 MyService规肴,這就是“控制反轉(zhuǎn)”(IoC)捶闸。

從 Client 的角度描述,Client 負(fù)責(zé) IValidator 的實(shí)例化奏纪,并將其注入到 MyService,這就是“依賴注入”(DI)斩启。

IoC其實(shí)就是把主動(dòng)變被動(dòng)序调,并有效的分離了對(duì)象和它所需要的外部資源,使得它們松散耦合兔簇,有利于功能復(fù)用发绢,更重要的是使得程序的整個(gè)體系結(jié)構(gòu)變得非常靈活。

除了通過構(gòu)造器注入外垄琐,還有另外兩種依賴注入方法边酒。

3.3 設(shè)值注入

設(shè)值注入是利用類成員變量的 setter 方法進(jìn)行依賴注入的一種方式。

代碼示例:

// IValidator.java
interface IValidator {
    public void validate(String param);
}

// NotnullValidator.java
class NotnullValidator implements IValidator{
    @Override
    public void validate(String param){
        System.out.println(this.getClass().getSimpleName()+ " validating param {"+param+"}");
        if(null == param || 0 == param.length()){
            System.out.println(this.getClass().getSimpleName() + " param can not be null or empty");
        }
    }
}

// MyService.java
class MyService {
    private IValidator validator;

    void setValidator(IValidator validator) {
        System.out.println("設(shè)值注入");
        this.validator = validator;
    }

    void Serve(String param){
        System.out.println(this.getClass().getSimpleName() + " param = " + param);
        validator.validate(param);
    }
}

// Client.java
public class Client {
    public static void main(String[] args){
        NotnullValidator notnullValidator = new NotnullValidator();
        MyService myService = new MyService();
        myService.setValidator(notnullValidator);
        myService.Serve("");
        myService.Serve("123");
        /**
         * 通過成員變量的setter方法注入依賴狸窘,叫做"設(shè)值注入"
         */
    }
}

這里墩朦,為 MyService 的成員變量 validator 定義了setValidator() 方法,從而使得外部可以通過這個(gè) setValidator() 方法注入 IValidator 依賴翻擒。

3.4 接口注入

接口注入是指氓涣,通過實(shí)現(xiàn)特定接口的依賴注入方法實(shí)現(xiàn)依賴注入的一種方式牛哺。

代碼示例:

// IValidator.java
interface IValidator {
    public void validate(String param);
}

// MyInject.java
interface MyInject {
    public void inject(IValidator validator);
}

// NotnullValidator.java
class NotnullValidator implements IValidator{
    @Override
    public void validate(String param){
        System.out.println(this.getClass().getSimpleName()+ " validating param {"+param+"}");
        if(null == param || 0 == param.length()){
            System.out.println(this.getClass().getSimpleName() + " param can not be null or empty");
        }
    }
}

// MyService.java
class MyService implements MyInject {
    private IValidator validator;

    void Serve(String param){
        System.out.println(this.getClass().getSimpleName() + " param = " + param);
        validator.validate(param);
    }

    @Override
    public void inject(IValidator validator) {
        System.out.println("接口注入");
        this.validator = validator;
    }
}

// Client.java
public class Client {
    public static void main(String[] args){
        NotnullValidator notnullValidator = new NotnullValidator();
        MyService myService = new MyService();
        myService.inject(notnullValidator);
        myService.Serve("");
        myService.Serve("123");
        /**
         * 通過實(shí)現(xiàn)一個(gè)單獨(dú)的依賴注入接口,實(shí)現(xiàn)依賴注入劳吠,叫做"接口注入"引润。
         * 不常見的用法,構(gòu)造函數(shù)和setter就夠用了痒玩。
         *
         * 通過構(gòu)造函數(shù)淳附、setter、接口注入依賴蠢古,仍然存在問題奴曙。
         * 加入一個(gè)類A依賴非常多的其他類,每一個(gè)都要手動(dòng)new便瑟,然后set缆毁,太麻煩了。
         * 怎么辦呢到涂?上框架脊框。
         */
    }
}

這里定義了一個(gè) MyInject 接口,接口內(nèi)部參數(shù) inject() 用于注入 IValidator 践啄。
MyService 實(shí)現(xiàn)了這個(gè)接口浇雹,Client 可以通過 inject() 注入IValidator 實(shí)例。

上面提到的三種注入方式:構(gòu)造子注入屿讽、設(shè)值注入昭灵、接口注入,實(shí)際上都是提供一個(gè)“入口”函數(shù)伐谈,允許外部調(diào)用方向內(nèi)注入 IValidator 依賴烂完,只是形式不同罷了。

但是诵棵,外部系統(tǒng)管理這些 “new” 操作的話抠蚣,如果接口內(nèi)有多層傳遞依賴,或者依賴項(xiàng)比較多的時(shí)候履澳,Client 負(fù)擔(dān)就太重了嘶窄。

怎么辦呢?上框架距贷。

IoC/DI 框架要做的事情柄冲,就是:new 什么,什么時(shí)候 new 忠蝗,new 完了要給誰现横。。。

IoC/DI 框架有很多长赞,這里主要介紹兩個(gè)晦攒,Spring 和 Guice。

4. IoC/DI 框架

4.1 spring

IoC是spring的核心得哆,對(duì)于spring框架來說脯颜,就是由 spring 來負(fù)責(zé)控制對(duì)象的生命周期和對(duì)象間的關(guān)系。

想要使用 spring 贩据,至少需要兩個(gè)核心包:group: 'org.springframework', name: 'spring-core'group: 'org.springframework', name: 'spring-context'栋操。

spring 通過一個(gè)叫做“容器”的東西來管理所有的 bean 對(duì)象。

當(dāng) Spring 應(yīng)用程序被加載到內(nèi)存中時(shí)饱亮,spring 框架通過讀取 “配置元數(shù)據(jù)”矾芙,來完成對(duì)象的實(shí)例化、配置和組裝近上。應(yīng)用程序可以從容器中取bean剔宪,方法是getBean()

在這里壹无,接口和類定義同上一章葱绒。
只是,額外增加 xml 配置文件用于定義 bean 的生命周期及依賴關(guān)系斗锭。

PS:“配置元數(shù)據(jù)” 可以通過 XML地淀、Java注解、Java代碼來標(biāo)識(shí)岖是,代碼示例只給出xml配置帮毁。

代碼有點(diǎn)多,我分開說哈豺撑。
記得以下幾步:

  1. 引入上面說的兩個(gè)包烈疚。
  2. 寫 java 代碼 定義 bean。
  3. 寫 xml 配置文件聪轿。
  4. Client爷肝。

構(gòu)建工具用的是gradle,所以這么引包:

// build.gradle
group 'com.ann.javas.topics'
version '1.0-SNAPSHOT'

apply plugin: 'java'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'org.springframework', name: 'spring-core', version: '4.3.11.RELEASE'
    compile group: 'org.springframework', name: 'spring-context', version: '4.3.11.RELEASE'
}

本例中屹电,給出了5種xml配置方法:構(gòu)造子注入阶剑、設(shè)值注入跃巡、自動(dòng)裝載byName危号,自動(dòng)裝載byType,自動(dòng)裝載constructor素邪。

先列下java代碼外莲,bean 定義沒變,就是Client.java里面的內(nèi)容多了點(diǎn):

// IValidator.java
public interface IValidator {
    public void validate(String param);
}

// NotnullValidator.java
public class NotnullValidator implements IValidator{
    @Override
    public void validate(String param) {
        System.out.println(this.getClass().getSimpleName()+ " validating param {"+param+"}");
        if(null == param || 0 == param.length()){
            System.out.println(this.getClass().getSimpleName() + " param can not be null or empty");
        }
    }
}

// MyService.java
public class MyService {
    private IValidator validator;

    public MyService(IValidator validator) {
        this.validator = validator;
    }

    public void setValidator(IValidator validator) {
        this.validator = validator;
    }

    public MyService() {
    }

    void Serve(String param){
        System.out.println(this.getClass().getSimpleName() + " param = " + param);
        validator.validate(param);
    }
}


// Client.java
public class Client {
    /**
     * 構(gòu)造子注入 和 設(shè)值注入,唯一的區(qū)別就是標(biāo)簽中定義依賴的元素不同偷线。
     * 構(gòu)造子注入使用:constructor-arg磨确,設(shè)值注入使用:property。
     *
     * @param args
     */
    public static void main(String[] args) {
        System.out.println("case1:測(cè)試spring容器構(gòu)造子注入(基于XML配置)...");
        demo1();
        System.out.println("..................................................");

        System.out.println("case2:測(cè)試spring容器設(shè)值注入(基于XML配置)...");
        demo2();
        System.out.println("..................................................");

        System.out.println("case3:測(cè)試spring容器自動(dòng)裝載byName(基于XML配置)...");
        demo3();
        System.out.println("..................................................");

        System.out.println("case4:測(cè)試spring容器自動(dòng)裝載byType(基于XML配置)...");
        demo4();
        System.out.println("..................................................");

        System.out.println("case5:測(cè)試spring容器自動(dòng)裝載constructor(基于XML配置)...");
        demo5();
        System.out.println("..................................................");

    }

    private static void demo1(){
        // 讀取配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("demo5_configioc-byxml-case1.xml");
        // 構(gòu)造子注入實(shí)例
        MyService service = (MyService)context.getBean("s");
        service.Serve("");
        service.Serve("123");
    }

    private static void demo2(){
        // 讀取配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("demo5_configioc-byxml-case2.xml");
        // 設(shè)值注入實(shí)例
        MyService service = (MyService)context.getBean("s");
        service.Serve("");
        service.Serve("123");
    }

    private static void demo3(){
        // 讀取配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("demo5_configioc-byxml-case3.xml");
        // 自動(dòng)裝載声邦,byName
        MyService service = (MyService)context.getBean("s");
        service.Serve("");
        service.Serve("123");
    }

    private static void demo4(){
        // 讀取配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("demo5_configioc-byxml-case4.xml");
        // 自動(dòng)裝載乏奥,byType
        MyService service = (MyService)context.getBean("s");
        service.Serve("");
        service.Serve("123");
    }

    private static void demo5(){
        // 讀取配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("demo5_configioc-byxml-case5.xml");
        // 自動(dòng)裝載,constructor
        MyService service = (MyService)context.getBean("s");
        service.Serve("");
        service.Serve("123");
    }
}

然后是xml配置文件亥曹,有5個(gè):

// demo5_configioc-byxml-case1.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 配置兩個(gè) bean邓了,并指明他們的依賴關(guān)系: MyService 依賴 NotnullValidator -->
    <!-- 被依賴的 NotnullValidator 會(huì)在 MyService 構(gòu)造之前構(gòu)造 -->
    <!-- 用 constructor-arg 配置,就是構(gòu)造子注入 -->
    <bean id="s" class="com.ann.javas.topics.iocdi.demo5.usespring.MyService">
        <constructor-arg ref="p"/>
    </bean>
    <bean id="p" class="com.ann.javas.topics.iocdi.demo5.usespring.NotnullValidator">
    </bean>
</beans>

// demo5_configioc-byxml-case2.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 配置兩個(gè) bean媳瞪,并指明他們的依賴關(guān)系: MyService 依賴 NotnullValidator -->
    <!-- 被依賴的 NotnullValidator 會(huì)在 MyService 構(gòu)造之前構(gòu)造 -->
    <!-- 用 property 配置骗炉,就是設(shè)值注入 -->
    <bean id="s" class="com.ann.javas.topics.iocdi.demo5.usespring.MyService">
        <property name="validator" ref="p"/>
    </bean>
    <bean id="p" class="com.ann.javas.topics.iocdi.demo5.usespring.NotnullValidator">
    </bean>
</beans>

// demo5_configioc-byxml-case3.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 配置兩個(gè) bean,并指明他們的依賴關(guān)系: MyService 依賴 NotnullValidator -->
    <!-- 被依賴的 NotnullValidator 會(huì)在 MyService 構(gòu)造之前構(gòu)造 -->
    <!-- 自動(dòng)裝載 byName蛇受,根據(jù) id 或 name 查找 bean 并自動(dòng)裝配 -->
    <bean id="s" class="com.ann.javas.topics.iocdi.demo5.usespring.MyService" autowire="byName">
    </bean>
    <!-- 這里的 id 必須和 MyService 中定義的IValidator 變量名一致句葵,否則 byName 無法識(shí)別 -->
    <bean id="validator" class="com.ann.javas.topics.iocdi.demo5.usespring.NotnullValidator">
    </bean>
</beans>

// demo5_configioc-byxml-case4.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 配置兩個(gè) bean,并指明他們的依賴關(guān)系: MyService 依賴 NotnullValidator -->
    <!-- 被依賴的 NotnullValidator 會(huì)在 MyService 構(gòu)造之前構(gòu)造 -->
    <!-- 自動(dòng)裝載byType兢仰,根據(jù) class 查找并自動(dòng)裝配 bean -->
    <bean id="s" class="com.ann.javas.topics.iocdi.demo5.usespring.MyService" autowire="byType">
    </bean>
    <bean id="b" class="com.ann.javas.topics.iocdi.demo5.usespring.NotnullValidator">
    </bean>
</beans>

// demo5_configioc-byxml-case5.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 配置兩個(gè) bean乍丈,并指明他們的依賴關(guān)系: MyService 依賴 NotnullValidator -->
    <!-- 被依賴的 NotnullValidator 會(huì)在 MyService 構(gòu)造之前構(gòu)造 -->
    <!-- 自動(dòng)裝載 constructor,根據(jù) bean 的構(gòu)造函數(shù)定義進(jìn)行查找并自動(dòng)裝配 -->
    <bean id="s" class="com.ann.javas.topics.iocdi.demo5.usespring.MyService" autowire="constructor">
    </bean>
    <bean id="b" class="com.ann.javas.topics.iocdi.demo5.usespring.NotnullValidator">
    </bean>
</beans>

代碼中的注釋有簡(jiǎn)單介紹旨别,詳細(xì)的內(nèi)容就不再贅述~

4.2 guice

guice 是谷歌開發(fā)的輕量級(jí) DI 框架诗赌,號(hào)稱比 spring 快10倍,雖然我沒測(cè)過秸弛,但確實(shí)蠻好用的就是了铭若。

想要使用guice,需要引包:group: 'com.google.inject', name: 'guice'

guice 允許你使用 @Inject 進(jìn)行注解構(gòu)造函數(shù)的方式递览,來進(jìn)行自動(dòng)實(shí)例化構(gòu)造參數(shù)叼屠。也可以通過實(shí)現(xiàn) Module 的 configure(Binder binder) 方法定義依賴注入規(guī)則。

在程序啟動(dòng)時(shí)绞铃,你可以使用 Guice.createInjector(自定義Module) 來生成一個(gè)injector镜雨,之后就可以從 injector 中獲取你需要 guice 為你實(shí)例化的類,方法是 injector.getInstance(你想要的類.class)儿捧。

用guice非常簡(jiǎn)單:

  1. 引包荚坞。
  2. java代碼。

同樣gradle構(gòu)建:

// build.gradle
group 'com.ann.javas.topics'
version '1.0-SNAPSHOT'

apply plugin: 'java'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'com.google.inject', name: 'guice', version: '4.0'
}

java代碼:

// IValidator.java
interface IValidator {
    public void validate(String param);
}

// NotnullValidator.java
class NotnullValidator implements IValidator {
    @Override
    public void validate(String param){
        System.out.println(this.getClass().getSimpleName()+ " validating param {"+param+"}");
        if(null == param || 0 == param.length()){
            System.out.println(this.getClass().getSimpleName() + " param can not be null or empty");
        }
    }
}


// MyService.java
class MyService  {
    @Inject
    private IValidator validator;

    void Serve(String param){
        System.out.println(this.getClass().getSimpleName() + " param = " + param);
        validator.validate(param);
    }
}


// MyModule.java
public class MyModule implements Module{
    @Override
    public void configure(Binder binder) {
        System.out.println("guice注入規(guī)則菲盾,綁定 IValidator 到 NotnullValidator");
        binder.bind(IValidator.class).to(NotnullValidator.class);
    }
}


// Client.java
public class Client {
    public static void main(String[] args){
        // 定義依賴注入規(guī)則
        MyModule module = new MyModule();

        // 根據(jù)注入規(guī)則颓影,生成 injector
        Injector injector = Guice.createInjector(module);

        // 獲取 MyService 實(shí)例
        MyService myService = injector.getInstance(MyService.class);

        // 來兩個(gè)case
        myService.Serve("");
        myService.Serve("123");
    }
}

如你所見,MyModule中定義了依賴注入規(guī)則懒鉴,將 IValidator 綁定到 NotnullValidator诡挂。這樣碎浇,當(dāng)某個(gè)類需要一個(gè)IValidator的時(shí)候,guice就會(huì)給它一個(gè)NotNullValidator實(shí)例璃俗。

其他的請(qǐng)看注釋說明~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末奴璃,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子城豁,更是在濱河造成了極大的恐慌苟穆,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,406評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件唱星,死亡現(xiàn)場(chǎng)離奇詭異鞭缭,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)魏颓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門岭辣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人甸饱,你說我怎么就攤上這事沦童。” “怎么了叹话?”我有些...
    開封第一講書人閱讀 167,815評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵偷遗,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我驼壶,道長(zhǎng)氏豌,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,537評(píng)論 1 296
  • 正文 為了忘掉前任热凹,我火速辦了婚禮泵喘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘般妙。我一直安慰自己纪铺,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,536評(píng)論 6 397
  • 文/花漫 我一把揭開白布碟渺。 她就那樣靜靜地躺著鲜锚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪苫拍。 梳的紋絲不亂的頭發(fā)上芜繁,一...
    開封第一講書人閱讀 52,184評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音绒极,去河邊找鬼骏令。 笑死,一個(gè)胖子當(dāng)著我的面吹牛集峦,可吹牛的內(nèi)容都是我干的伏社。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼塔淤,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼摘昌!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起高蜂,我...
    開封第一講書人閱讀 39,668評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤聪黎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后备恤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體稿饰,經(jīng)...
    沈念sama閱讀 46,212評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,299評(píng)論 3 340
  • 正文 我和宋清朗相戀三年露泊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了喉镰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,438評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡惭笑,死狀恐怖侣姆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情沉噩,我是刑警寧澤捺宗,帶...
    沈念sama閱讀 36,128評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站川蒙,受9級(jí)特大地震影響蚜厉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜畜眨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,807評(píng)論 3 333
  • 文/蒙蒙 一昼牛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧康聂,春花似錦匾嘱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蕊连,卻和暖如春悬垃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背甘苍。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工尝蠕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人载庭。 一個(gè)月前我還...
    沈念sama閱讀 48,827評(píng)論 3 376
  • 正文 我出身青樓看彼,卻偏偏與公主長(zhǎng)得像廊佩,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子靖榕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,446評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容