时间:2017年10月14日星期六
说明:本文部份内容均来自慕课网。@慕课网:http://www.imooc.com
教学源码:https://github.com/zccodere/s...
学习源码:https://github.com/zccodere/s...java
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
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
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>
经典Hello World分析
核心算法:将指定内容输出至指定目标
改造Hello World程序
面向对象化 消除Dependency 用Guice来配置Dependency
代码编写
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:重命名 先写代码,再让其编译经过 先思考肯定须要什么,而后再机械性劳动实现 函数命名 从实现角度:精确描述函数干什么 从调用者角度:描述调用者需求 二者不匹配:须要进行抽象的点
代码编写
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地址查看
注入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()); } }
绑定图解
绑定
类名绑定 实例绑定 链接绑定 Provider绑定 命名绑定 泛型绑定 集合绑定
Module的相互关系
并列:Guice.createInjector(module1,module2,…) 嵌套:install(module) 覆盖:Modules.override(module1).with(module2)
Module什么时候被运行
Module里存放了不少表达式 Module不被“运行” Guice.createInjector()时记录全部表达式
系统什么时候初始化
没有“初始化”概念,没有Spring的Configuration Time injector.getInstance()时根据表达式调用构造函数
案例: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地址查看
生命周期或做用域
选择做用域
默认:适用于:通常实例,stateless,构造速度快 如:Parser、PriceCalulator Singleton:适用于:stateful的实例,构造速度慢的实例,必须线程安全 如:数据库、网络链接 Session/Request:含有session/request信息的实例、stateful的实例 如:SessionSate
做用域的使用
做为类或者@Provides方法的属性 在绑定时使用In语句 @Singleton的线程安全性
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()); } }
使用Guice与SpringBoot协做搭建Web应用
使用SpringBoot搭建简单的Web应用 使用Guice搭建业务逻辑
协做框架
建立名为guicespring的maven工程
完成后的项目结构以下
受篇幅限制,源码请到个人github地址查看
协做小结
SpringBoot进行总控 各自绑定Guice Injector和Spring ApplicationContext 注意对象生命周期
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 与其它组件或解决方案整合:注意对象生命周期
课程回顾
什么是Guce Dependency Injection:改造Hello World程序 注入(Injection) 绑定(Binding) 做用域或生命周期(Scope) Guice AOP 使用Guice与SpringBoot协做搭建Web应用