慕课网《使用Google Guice实现依赖注入》学习总结
时间:2017年10月14日星期六
说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com
教学源码:https://github.com/zccodere/study-imooc
学习源码:https://github.com/zccodere/study-imooc
第一章:课程介绍
1-1 课程简介
Google Guice:Guice是啥
Guice读音:juice
Guice is a lightweight dependency injection framework for java
Guice 是轻量级的依赖注入框架
Google Guice:说明
Java:一个java的框架、需要有java基础
dependency injection:什么是dependency、剥离dependency、注入dependency
lightweight:轻量级(代码少、易维护、性能优异),跟Spring比较。
但是:学习曲线陡峭、对开发者的要求太高了
课程目标
理解、重新理解dependency injection
掌握Guice的语法,更要掌握Guice的设计理念
开始在你的下一个项目中使用Guice
课程要点
什么是Guice
dependency injection:改造Hello World程序
注入(Injection)
绑定(Binding)
作用域或生命周期(Scope)
Guice AOP
使用Guice和SpringBoot协作搭建一个简单的Web应用
Guice vs Spring
1-2 产生原因
Spring的不足
手动配置:使用xml进行配置,配置太过庞大
自动配置:Spring提供了自动配置,复杂项目无法实现
Guice不同于Spring
取消xml
取消bean的概念
使用Constructor来注入
泛型支持
一个专注于Dependency Injection的框架
参考资料
https://github.com/google/guice/wiki/Motivation
https://github.com/google/guice/wiki/ExternalDocumentation
更多利用英文资料,如Stackoverflow
第二章:理解依赖
2-1 基础配置
Hello Guice
配置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分析
核心算法:将指定内容输出至指定目标
改造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小结
代码编写
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小结
注入图解
注入(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
如何注入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 绑定详解
绑定图解
绑定
类名绑定
实例绑定
连接绑定
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 基本介绍生命周期或作用域
选择作用域
默认:适用于:一般实例,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搭建业务逻辑
协作框架
创建名为guicespring的maven工程
完成后的项目结构如下
受篇幅限制,源码请到我的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应用
热门评论
感谢分享,很详细啊!