时间:2017年10月14日星期六
说明:本文部分内容均来自慕课网。@慕课网: 教学源码:学习源码:第一章:课程介绍
1-1 课程简介
Google Guice:Guice是啥
Guice读音:juiceGuice is a lightweight dependency injection framework for javaGuice 是轻量级的依赖注入框架
Google Guice:说明
Java:一个java的框架、需要有java基础dependency injection:什么是dependency、剥离dependency、注入dependencylightweight:轻量级(代码少、易维护、性能优异),跟Spring比较。但是:学习曲线陡峭、对开发者的要求太高了
课程目标
理解、重新理解dependency injection掌握Guice的语法,更要掌握Guice的设计理念开始在你的下一个项目中使用Guice
课程要点
什么是Guicedependency 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/Motivationhttps://github.com/google/guice/wiki/ExternalDocumentation更多利用英文资料,如Stackoverflow
第二章:理解依赖
2-1 基础配置
Hello Guice
配置Guice环境Dependency Injection基础改造Hello World
创建名为guicedemo的maven工程pom如下
4.0.0 com.myimooc guicedemo 0.0.1-SNAPSHOT jar guicedemo http://maven.apache.org UTF-8 1.8 1.8 1.8 com.google.inject guice 4.1.0 com.google.inject.extensions guice-multibindings 4.1.0 junit junit 4.12 test
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小结
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 ProviderstringProvider; @Inject public StringWritingApplet(MyDestination destination,@Output Provider 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)@BindingAnnotationpublic @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小结
第三章:注入依赖
3-1 基本注入
注入图解
注入(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 dbConnProvider< DatabaseConnection > dbConnProviderGuice会考虑对象生命周期需要时可以自己实现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 ProvidersessionIdProvider; @Inject public SessionManager(@SessionId Provider 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)@BindingAnnotationpublic @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 Timeinjector.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、PriceCalulatorSingleton:适用于: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搭建业务逻辑
协作框架
7-2 案例实战
创建名为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 课程回顾
课程回顾
什么是GuceDependency Injection:改造Hello World程序注入(Injection)绑定(Binding)作用域或生命周期(Scope)Guice AOP使用Guice与SpringBoot协作搭建Web应用