PlayFramework 已全面向 Google Guice 演进, 由于我们的项目是从 Play 2.0 开始搭建, 现虽已升级到了 2.4.6, 但对 Guice 的还没抱得那么的紧, 有点积重而慢步前挪. Google Guice 也是一个依赖注入(DI) 容器, 据说它比 Spring 快了很多很多, 是轻量级项目或框架首选, Google 出品俱是精品.
既然它是轻量级的 DI, 那么必须呈上一个最轻量级的入门, 官方的 Get Started 文档其实啰嗦了点, 对于 BillingService 依赖的 CreditCardProcess, TransactionLog, 和 Receipt 都未有交待, 算不上一个完整项目. 所以我这里尽量简化, 又不偏离一个最简单的项目模型. 那就是下面那个例子, 它实现了在不同时间发出不同的问候.
项目需要依赖 Guice 及它的子依赖, 这得看你是用什么来管理依赖的, 依照 http://mvnrepository.com/artifact/com.google.inject/guice/4.0 根据实际情况加上依赖配置, 前面这个链接默认为 sbt 的, 我还真偏爱了 sbt, 若是 Maven 就配置 Maven 的 pom.xml 吧. Guice 的引入带上以下几个依赖包
+-com.google.inject:guice:4.0
+-aopalliance:aopalliance:1.0
+-com.google.guava:guava:16.0.1
+-javax.inject:javax.inject:1
Guice 目前是 4.0.
然后在这个 Hello World 项目中有以下几个类
├── Client.java
├── HelloModule.java
├── TimeWindow.java
├── Morning.java
└── HelloService.java
它们的内容分别如下:
TimeWindow.java
1 2 3 |
public interface TimeWindow { String message(); } |
Morning.java
1 2 3 4 5 6 7 |
public class Morning implements TimeWindow { @Override public String message() { return "Morning"; } } |
service/HelloService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import com.google.inject.Inject; public class HelloService { private final TimeWindow timeWindow; @Inject public HelloService(TimeWindow timeWindow) { this.timeWindow = timeWindow; } public String sayHello() { return "Good " + timeWindow.message(); } } |
@Inject
注明了这是一个注入依赖(初始化该实例的入口). 这里是通过构造函数来注入的, 也可以通过 setter 方法注入属性, 或直接注入属性.
好了, 脚手架已准备就位, 现在看怎么撮合上面那些类, 首先用来初始化 DI 容器的
HelloModule.java
1 2 3 4 5 6 7 8 9 |
import com.google.inject.AbstractModule; public class HelloModule extends AbstractModule { @Override protected void configure() { bind(TimeWindow.class).to(Morning.class); } } |
粗略能明白上面的意图, 即要 TimeWindow 类型的地方给个 Morning 实例. 它是一个继承自 AbstractModuel
的类.
最后的最后就是运行起来
Client.java
1 2 3 4 5 6 7 8 9 10 |
import com.google.inject.*; public class Client { public static void main(String[] args) { Injector injector = Guice.createInjector(new HelloModule()); HelloService helloService = injector.getInstance(HelloService.class); System.out.println(helloService.sayHello()); } } |
三步, 1) 加载模块, 按照模块中的绑定关系来创建 Guice 容器, 即 Injector
, creteInjector()
是一个可变参方法, 所以它可以同时加载多个模块; 2) 根据类型从容器中查找到想要的实例; 3) 使用它
执行上面的 Client
能打印出 Good Morning
, 说明 HelloService 能顺利被初始化, 并且 Morning
也成功被注入到 HelloService. HelloService 的构造函数因为有 @Inject
注解, 所以也可由 Guice 构造出来, 这是自动的.
到此 Google Guice 的 Hello World 便全部完成, 基础框架如此, 剩下就是一些实用性的技巧了. 实际运用中势必要遇到各种问题, Hello World 只是个雏形, 离实际应用还远着呢, 所以碰到问题应该可以从官方的 user's guide 找到答案.
不妨列出几个来备忘, 不作展开:
- 用自定义标签和 @Named 指定属性绑定
- 直接绑定属性值, 这样就不用借助于接口去绑定实现
- @Provides 标注的方或 Provider 实现类的返回值注入给相应的类型
- in(Singleton.class)/@Singleton 标明是单例类, asEagerSingleton() 立即初始化类
- 指定构造方法来初始化实例
- 即时绑定, 这条很强大. 如果具体类有默认构造, 或非默认构造用 @Inject 标注了, 不写绑定, Guice 的 injector.getInstance(AnyClass.class) 就能为你提供实例
- @ImplementedBy, @ProvideBy 为类型指定具体实现类或提供者
- 等等......
本文链接 https://yanbin.blog/google-guice-hello-world/, 来自 隔叶黄莺 Yanbin Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。