慕課網_《使用Google Guice實現依賴注入》學習總結

時間:2017年10月14日星期六
說明:本文部份內容均來自慕課網。@慕課網:http://www.imooc.com
教學源碼:https://github.com/zccodere/s...
學習源碼:https://github.com/zccodere/s...java

第一章:課程介紹

1-1 課程簡介

Google Guice:Guice是啥git

Guice讀音:juice
Guice is a lightweight dependency injection framework for java
Guice 是輕量級的依賴注入框架

Google Guice:說明github

Java:一個java的框架、須要有java基礎
dependency injection:什麼是dependency、剝離dependency、注入dependency
lightweight:輕量級(代碼少、易維護、性能優異),跟Spring比較。
可是:學習曲線陡峭、對開發者的要求過高了

課程目標算法

理解、從新理解dependency injection
掌握Guice的語法,更要掌握Guice的設計理念
開始在你的下一個項目中使用Guice

課程要點spring

什麼是Guice
dependency injection:改造Hello World程序
注入(Injection)
綁定(Binding)
做用域或生命週期(Scope)
Guice AOP
使用Guice和SpringBoot協做搭建一個簡單的Web應用
Guice vs Spring

1-2 產生緣由

Spring的不足數據庫

手動配置:使用xml進行配置,配置太過龐大
自動配置:Spring提供了自動配置,複雜項目沒法實現

Guice不一樣於Springapache

取消xml
取消bean的概念
使用Constructor來注入
泛型支持
一個專一於Dependency Injection的框架

參考資料編程

https://github.com/google/guice/wiki/Motivation
https://github.com/google/guice/wiki/ExternalDocumentation
更多利用英文資料,如Stackoverflow

第二章:理解依賴

2-1 基礎配置

Hello Guicebootstrap

配置Guice環境
Dependency Injection基礎
改造Hello World

建立名爲guicedemo的maven工程pom以下安全

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.myimooc</groupId>
    <artifactId>guicedemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>guicedemo</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.google.inject</groupId>
            <artifactId>guice</artifactId>
            <version>4.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.inject.extensions</groupId>
            <artifactId>guice-multibindings</artifactId>
            <version>4.1.0</version>
        </dependency>
        
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

2-2 依賴分析

經典Hello World分析

clipboard.png

核心算法:將指定內容輸出至指定目標

改造Hello World程序

面向對象化
消除Dependency
用Guice來配置Dependency

2-3 面向對象

代碼編寫

1.編寫MyApplet類

package com.myimooc.guicedemo;

/**
 * @title Applet類
 * @describe 提供run()方法
 * @author zc
 * @version 1.0 2017-10-15
 */
public interface MyApplet extends Runnable{
    
}

2.編寫HelloWorldPrinter類

package com.myimooc.guicedemo.helloworlddemo;

import com.myimooc.guicedemo.MyApplet;

/**
 * @title HelloWorldPrinter類
 * @describe 提供打印HelloWorld的功能
 * @author zc
 * @version 1.0 2017-10-15
 */
public class HelloWorldPrinter implements MyApplet {
    
    private void printHelloWorld() {
        System.out.println("Hello World!");
    }
    
    @Override
    public void run() {
        printHelloWorld();
    }
}

3.編寫Configuration類

package com.myimooc.guicedemo;

import com.myimooc.guicedemo.helloworlddemo.HelloWorldPrinter;

/**
 * @title Configuration類
 * @describe 程序啓動配置類
 * @author zc
 * @version 1.0 2017-10-15
 */
public class Configuration {
    
    public static MyApplet getMainApplet() {
        return new HelloWorldPrinter();
    }
    
}

4.編寫App類

package com.myimooc.guicedemo;

/**
 * @title 啓動類
 * @describe 改造HelloWorld類
 * @author zc
 * @version 1.0 2017-10-15
 */
public class App {
    /**
     * main方法的做用
     * bootstrap:
     *   parse command line:解析命令行參數
     *   set up environment:配置環境參數
     *   kick off main logic:啓動程序邏輯
     * @param args
     */
    public static void main(String[] args) {
        MyApplet mainApplet = Configuration.getMainApplet();
        mainApplet.run();
    }
}

面向對象化小結

善於運用IDE提供的重構能力
    Ctrl + 1:猜想下一步動做
    Ctrl + shift + r:重命名
    先寫代碼,再讓其編譯經過
    先思考肯定須要什麼,而後再機械性勞動實現
函數命名
    從實現角度:精確描述函數幹什麼
    從調用者角度:描述調用者需求
    二者不匹配:須要進行抽象的點

2-4 提取依賴

代碼編寫

1.編寫MyApplet類

package com.myimooc.guicedemo.noguice;

/**
 * @title MyApplet類
 * @describe 提供run()方法
 * @author zc
 * @version 1.0 2017-10-15
 */
public interface MyApplet extends Runnable{
    
}

2.編寫StringWritingApplet類

package com.myimooc.guicedemo.noguice.helloworlddemo;

import com.myimooc.guicedemo.noguice.MyApplet;

/**
 * @title HelloWorldPrinter類
 * @describe 提供打印HelloWorld的功能
 * @author zc
 * @version 1.0 2017-10-15
 */
public class StringWritingApplet implements MyApplet {
    
    private MyDestination destination;
    private StringProvider stringProvider;
    
    public StringWritingApplet(MyDestination destination,StringProvider stringProvider) {
        super();
        this.destination = destination;
        this.stringProvider = stringProvider;
    }

    private void writeString() {
        destination.write(stringProvider.get());
    }
    
    @Override
    public void run() {
        writeString();
    }
}

3.編寫StringProvider類

package com.myimooc.guicedemo.noguice.helloworlddemo;

/**
 * @title StringProvider類
 * @describe 提供get()方法
 * @author zc
 * @version 1.0 2017-10-15
 */
public interface StringProvider {

    String get();

}

4.編寫MyDestination類

package com.myimooc.guicedemo.noguice.helloworlddemo;

/**
 * @title MyDestination類
 * @describe 提供write()方法
 * @author zc
 * @version 1.0 2017-10-15
 */
public interface MyDestination {

    void write(String string);

}

5.編寫PrintStreamWriter類

package com.myimooc.guicedemo.noguice.helloworlddemo;

import java.io.PrintStream;

/**
 * @title PrintStreamWriter類
 * @describe 實現write()方法
 * @author zc
 * @version 1.0 2017-10-15
 */
public class PrintStreamWriter implements MyDestination {

    private PrintStream destination;
    
    public PrintStreamWriter(PrintStream destination) {
        super();
        this.destination = destination;
    }

    @Override
    public void write(String string) {
        destination = System.out;
        destination.println(string);
    }
}

6.編寫Configuration類

package com.myimooc.guicedemo.noguice;

import com.myimooc.guicedemo.noguice.helloworlddemo.PrintStreamWriter;
import com.myimooc.guicedemo.noguice.helloworlddemo.StringProvider;
import com.myimooc.guicedemo.noguice.helloworlddemo.StringWritingApplet;

/**
 * @title Configuration類
 * @describe 程序啓動配置類
 * @author zc
 * @version 1.0 2017-10-15
 */
public class Configuration {
    
    public static MyApplet getMainApplet() {
        return new StringWritingApplet(
               new PrintStreamWriter(System.out),
               new StringProvider() {
                    @Override
                    public String get() {
                        return "Hello World";
                    }
                });
    }
}

7.編寫App類

package com.myimooc.guicedemo.noguice;

/**
 * @title 啓動類
 * @describe 改造HelloWorld類
 * @author zc
 * @version 1.0 2017-10-15
 */
public class App {
    /**
     * main方法的做用
     * bootstrap:
     *   parse command line:解析命令行參數
     *   set up environment:配置環境參數
     *   kick off main logic:啓動程序邏輯
     * @param args
     */
    public static void main(String[] args) {
        MyApplet mainApplet = Configuration.getMainApplet();
        mainApplet.run();
    }
}

消除Dependency小結

clipboard.png

2-5 配置依賴

代碼編寫

1.編寫MyApplet類

package com.myimooc.guicedemo.useguice;

/**
 * @title MyApplet類
 * @describe 提供run()方法
 * @author zc
 * @version 1.0 2017-10-15
 */
public interface MyApplet extends Runnable{
    
}

2.編寫StringWritingApplet類

package com.myimooc.guicedemo.useguice.helloworlddemo;

import com.google.inject.Inject;
import com.google.inject.Provider;
import com.myimooc.guicedemo.useguice.MyApplet;

/**
 * @title HelloWorldPrinter類
 * @describe 提供打印HelloWorld的功能
 * @author zc
 * @version 1.0 2017-10-15
 */
public class StringWritingApplet implements MyApplet {
    
    private MyDestination destination;
    private Provider<String> stringProvider;
    
    @Inject
    public StringWritingApplet(MyDestination destination,@Output Provider<String> stringProvider) {
        super();
        this.destination = destination;
        this.stringProvider = stringProvider;
    }

    private void writeString() {
        destination.write(stringProvider.get());
    }
    
    @Override
    public void run() {
        writeString();
    }
}

3.編寫MyDestination類

package com.myimooc.guicedemo.useguice.helloworlddemo;

/**
 * @title MyDestination類
 * @describe 提供write()方法
 * @author zc
 * @version 1.0 2017-10-15
 */
public interface MyDestination {

    void write(String string);

}

4.編寫PrintStreamWriter類

package com.myimooc.guicedemo.useguice.helloworlddemo;

import java.io.PrintStream;

import javax.inject.Inject;

/**
 * @title PrintStreamWriter類
 * @describe 實現write()方法
 * @author zc
 * @version 1.0 2017-10-15
 */
public class PrintStreamWriter implements MyDestination {

    private PrintStream destination;
    
    @Inject
    public PrintStreamWriter(PrintStream destination) {
        super();
        this.destination = destination;
    }

    @Override
    public void write(String string) {
        destination = System.out;
        destination.println(string);
    }
}

5.編寫Output類

package com.myimooc.guicedemo.useguice.helloworlddemo;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import com.google.inject.BindingAnnotation;

/**
 * @title Output註解
 * @describe 
 * @author zc
 * @version 1.0 2017-10-15
 */
@Retention(RetentionPolicy.RUNTIME)
@BindingAnnotation
public @interface Output {

}

6.編寫HelloWorldModule類

package com.myimooc.guicedemo.useguice.helloworlddemo;

import java.io.PrintStream;

import com.google.inject.AbstractModule;
import com.myimooc.guicedemo.useguice.MyApplet;

/**
 * @title HelloWorldModule類
 * @describe HelloWorld模塊的依賴配置
 * @author zc
 * @version 1.0 2017-10-15
 */
public class HelloWorldModule extends AbstractModule{
    
    @Override
    protected void configure() {
        bind(MyApplet.class).to(StringWritingApplet.class);
        bind(MyDestination.class).to(PrintStreamWriter.class);
        bind(PrintStream.class).toInstance(System.out);
        bind(String.class).annotatedWith(Output.class).toInstance("Hello World");
    }
}

7.編寫MainModule類

package com.myimooc.guicedemo.useguice;

import com.google.inject.AbstractModule;
import com.myimooc.guicedemo.useguice.helloworlddemo.HelloWorldModule;

/**
 * @title MainModule類
 * @describe Guice用來配置的類
 * @author zc
 * @version 1.0 2017-10-15
 */
public class MainModule extends AbstractModule{

    @Override
    protected void configure() {
        install(new HelloWorldModule());
    }
}

8.編寫App類

package com.myimooc.guicedemo.useguice;

import com.google.inject.Guice;

/**
 * @title 啓動類
 * @describe 改造HelloWorld類
 * @author zc
 * @version 1.0 2017-10-15
 */
public class App {
    /**
     * main方法的做用
     * bootstrap:
     *   parse command line:解析命令行參數
     *   set up environment:配置環境參數
     *   kick off main logic:啓動程序邏輯
     * @param args
     */
    public static void main(String[] args) {
        MyApplet mainApplet = Guice
                .createInjector(new MainModule())
                .getInstance(MyApplet.class);
        mainApplet.run();
    }
}

Guice配置Dependency小結

clipboard.png

第三章:注入依賴

3-1 基本注入

注入圖解

clipboard.png

注入(Injection)

構造函數注入
    使用final來區分dependency和狀態
    注入時不考慮如何實現或綁定
成員變量注入
    用於測試
    使用injectMembers來注入測試用例

代碼編寫

1.編寫OrderService類

2.編寫PaymentService類

3.編寫PriceService類

4.編寫OrderServiceImpl類

5.編寫PaymentServiceImpl類

6.編寫PriceServiceImpl類

7.編寫SessionManager類

8.編寫ServerModule類

9.編寫OrderServiceTest類

受篇幅限制,源碼請到個人github地址查看

3-2 其餘注入

注入Provider

clipboard.png

如何注入Provider

DatabaseConnection dbConn
Provider< DatabaseConnection > dbConnProvider
Guice會考慮對象生命週期
須要時能夠本身實現Provider

命名注入

@Inject @Named(「dbSpec」) private String dbSpec;
@Inject @LogFileName private String logFileName;
使用@Named:參數來自配置文件或命令行、或者爲了開發方便
使用屬性:一般採用此方法

代碼編寫

1.修改SessionManager類

package com.myimooc.guicedemo.server.impl;

import javax.inject.Inject;

import com.google.inject.Provider;

/**
 * @title session管理類
 * @describe 模擬訂單系統
 * @author zc
 * @version 1.0 2017-10-15
 */
public class SessionManager {
    
    private final Provider<Long> sessionIdProvider;
    
    @Inject
    public SessionManager(@SessionId Provider<Long> sessionIdProvider) {
        super();
        this.sessionIdProvider = sessionIdProvider;
    }

    public Long getSessionId() {
        return sessionIdProvider.get();
    }

}

2.修改ServerModule類

package com.myimooc.guicedemo.server.impl;

import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.myimooc.guicedemo.server.OrderService;
import com.myimooc.guicedemo.server.PaymentService;
import com.myimooc.guicedemo.server.PriceService;

/**
 * @title ServerModule類
 * @describe 綁定依賴
 * @author zc
 * @version 1.0 2017-10-15
 */
public class ServerModule extends AbstractModule{

    @Override
    protected void configure() {
        bind(OrderService.class).to(OrderServiceImpl.class);
        bind(PaymentService.class).to(PaymentServiceImpl.class);
        bind(PriceService.class).to(PriceServiceImpl.class);
    }
    
    @Provides 
    @SessionId
    Long generateSessionId(){
        return System.currentTimeMillis();
    }
}

3.編寫SessionId類

package com.myimooc.guicedemo.server.impl;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import com.google.inject.BindingAnnotation;

/**
 * @title SessionId註解
 * @describe 用來綁定數據
 * @author zc
 * @version 1.0 2017-10-15
 */
@Retention(RetentionPolicy.RUNTIME)
@BindingAnnotation
public @interface SessionId {

}

4.編寫SessionManagerTest類

package com.myimooc.guicedemo.server.impl;

import static org.junit.Assert.assertNotEquals;

import javax.inject.Inject;

import org.junit.Before;
import org.junit.Test;

import com.google.inject.Guice;

/**
 * @title 測試類
 * @describe 測試@Provides
 * @author zc
 * @version 1.0 2017-10-15
 */
public class SessionManagerTest {
    
    @Inject
    SessionManager sessionManager;
    
    @Before
    public void setUp(){
        Guice.createInjector(new ServerModule())
             .injectMembers(this);
    }
    
    @Test
    public void testGetSessionId() throws InterruptedException{
        Long sessionId1 = sessionManager.getSessionId();
        Thread.sleep(1000);
        Long sessionId2 = sessionManager.getSessionId();
        assertNotEquals(sessionId1.longValue(), sessionId2.longValue());
    }
    
}

第四章:綁定依賴

4-1 綁定詳解

綁定圖解

clipboard.png

綁定

類名綁定
實例綁定
鏈接綁定
Provider綁定
命名綁定
泛型綁定
集合綁定

4-2 模塊組織

Module的相互關係

並列:Guice.createInjector(module1,module2,…)
嵌套:install(module)
覆蓋:Modules.override(module1).with(module2)

Module什麼時候被運行

Module裏存放了不少表達式
Module不被「運行」
Guice.createInjector()時記錄全部表達式

系統什麼時候初始化

沒有「初始化」概念,沒有Spring的Configuration Time
injector.getInstance()時根據表達式調用構造函數

4-3 綁定示例

案例:HelloWorld與命令行

讓HelloWorld打印命令行參數
讓HelloWorld經過命令行決定啓動哪一個Applet

代碼編寫

1.編寫MyApplet類

2.編寫Applets類

3.編寫StringWritingApplet類

4.編寫PrintLineApplet類

5.編寫MyDestination類

6.編寫PrintStreamWriter類

7.編寫Output類

8.編寫Args類

9.編寫HelloWorldModule類

10.編寫PrintLineModule類

11.編寫CommandLineModule類

12.編寫MainModule類

13.編寫App類

受篇幅限制,源碼請到個人github地址查看

第五章:生命週期

5-1 基本介紹

生命週期或做用域

clipboard.png

clipboard.png

選擇做用域

默認:適用於:通常實例,stateless,構造速度快
如:Parser、PriceCalulator
Singleton:適用於:stateful的實例,構造速度慢的實例,必須線程安全
如:數據庫、網絡鏈接
Session/Request:含有session/request信息的實例、stateful的實例
如:SessionSate

5-2 使用介紹

做用域的使用

做爲類或者@Provides方法的屬性
在綁定時使用In語句
@Singleton的線程安全性

第六章:切面編程

6-1 面向切面

Guice AOP

符合AOP Alliance的MethodInterceptor接口
MethodInterceptor可用於「Aspects」
    獲取函數調用類、方法、參數
    控制是否執行函數調用

實現AOP

綁定MethodInterceptor
實現MethodInterceptor
在MethodInterceptor中注入Dependency

代碼編寫

1.編寫Logged類

package com.myimooc.guicedemo.aop;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * @title Logged註解
 * @describe 用於標識須要記錄日誌的方法
 * @author zc
 * @version 1.0 2017-10-15
 */
@Retention(RetentionPolicy.RUNTIME)
public @interface Logged {
    
}

2.編寫LoggedInterceptor類

package com.myimooc.guicedemo.aop;

import java.lang.reflect.Method;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import com.google.common.base.Joiner;

/**
 * @title LoggedMethodInterceptor類
 * @describe 切面類,用於處理被攔截的方法,實現日誌記錄
 * @author zc
 * @version 1.0 2017-10-15
 */
public class LoggedInterceptor implements MethodInterceptor{

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        
        // 得到調用參數
        invocation.getArguments();
        // 得到調用對象
        invocation.getClass();
        // 得到調用方法
        Method method = invocation.getMethod();
        
        // 記錄日誌
        System.out.println(String.format("Calling %s#%s(%s)",
            method.getDeclaringClass().getName(),
            method.getName(),
            Joiner.on(",").join(invocation.getArguments())));
        
        // 執行調用方法
        Object result = invocation.proceed();
        
        // 返回調用結果
        return result;
    }
}

3.編寫LoggedModule類

package com.myimooc.guicedemo.aop;

import com.google.inject.AbstractModule;
import com.google.inject.matcher.Matchers;

/**
 * @title LoggedModule類
 * @describe 用於配置依賴綁定
 * @author zc
 * @version 1.0 2017-10-15
 */
public class LoggedModule extends AbstractModule{

    @Override
    protected void configure() {
        
        // 配置攔截任意類,帶有@Logged註解修飾的方法
        bindInterceptor(
            Matchers.any(), 
            Matchers.annotatedWith(Logged.class), 
            new LoggedInterceptor());
        
    }
}

第七章:框架集成

7-1 協做框架

使用Guice與SpringBoot協做搭建Web應用

使用SpringBoot搭建簡單的Web應用
使用Guice搭建業務邏輯

協做框架

clipboard.png

7-2 案例實戰

建立名爲guicespring的maven工程

完成後的項目結構以下

clipboard.png

受篇幅限制,源碼請到個人github地址查看

協做小結

SpringBoot進行總控
各自綁定Guice Injector和Spring ApplicationContext
注意對象生命週期

第八章:課程總結

8-1 適用場景

Guice與Spring

Guice不是Spring的重製版
Spring綁定
    配置文件體現完整裝配結構
    大量使用字符串:實例名:屬性名
    在Config Time完成組裝
Guice綁定
    Java代碼描述綁定規則
    每一個注入和綁定僅描述局部依賴
    沒有Config Time

Guice的優勢

代碼量少
性能優異
支持泛型
Constructor綁定:Immutable objects,再也不須要getter/setter
強類型
易於重構

Guice的缺點

Module和綁定規則不易理解
文檔教程少,社區資源少
沒法方便搭出特殊結構:如循環依賴
Guice僅僅是依賴注入框架,而Spring涵蓋較多

從Spring遷移到Guice

不建議
Spring與Guice整合

新項目須要選擇Dependency Injection方案

不妨嘗試Guice
與其它組件或解決方案整合:注意對象生命週期

8-2 課程回顧

課程回顧

什麼是Guce
Dependency Injection:改造Hello World程序
注入(Injection)
綁定(Binding)
做用域或生命週期(Scope)
Guice AOP
使用Guice與SpringBoot協做搭建Web應用
相關文章
相關標籤/搜索