Guice之IOC教程
Guice
在上一篇博客中, 我们讲解了Spring中的IOC示例与实现, 本文着重介绍Guice注入以及与Spring中的差异.
Guice是Google开发的, 一个轻量级的依赖注入框架, 跟Spring最大的区别在于脱离xml配置,
大量使用Annotation来实现注入, 支持属性, 构造器, setter等多种方式注入对象.
Guice 3.0支持 jdk 1.6, 如果运行报错ClassNotFoundException: javax.inject.Provider, 则需要导入javax.inject包.
Module容器
Guice中容器即Module, 用于绑定接口 : 实现类, 类似于Spring中的applicationContext.xml.
Module像是一个Map,根据一个Key获取其Value,清楚明了的逻辑.
以下代码实现了一个简单的注入
1 Injector ij = Guice.createInjector(new Module() {
2 @Override
3 public void configure(Binder binder) {
4 binder.bind(TestService.class).to(ServiceImpl.class);
5 }
6 });
7 ij.getInstance(TestService.class).test();
支持绕过Module, 用默认配置, 直接实例化对象, 不过没啥意义, 除非要用容器做aop
1 Injector ij2 = Guice.createInjector();
2 ij2.getInstance(ServiceImpl.class).test();
当然也可以使用注解的方式来声明接口的实现类, 然后Injector 从接口中获取对象,
意义也不大, 因为实际业务中, 接口可能在上层包里, 无法直接调用实现类.
1 @ImplementedBy(ServiceImpl.class)
2 public interface TestService {
3
4 void test();
5 }
6
7 ---------------------------------------
8
9 Injector ij3 = Guice.createInjector();
10 ij3.getInstance(TestService.class).test();
@Inject属性注入
1 public class GuiceObjectDemo {
2
3 @Inject
4 private TestService service1;
5 @Inject
6 private TestService service2;
7
8 ---------------------------------------
9
10 GuiceObjectDemo demo = Guice.createInjector().getInstance(GuiceObjectDemo.class);
11 System.out.println(demo.getService());
12 System.out.println(demo.getService2());
属性注入的时候, 必须通过Guice.createInjector().getInstance(GuiceObjectDemo.class);来获取实现类, 如果直接new的话, 会inject失败, 打印出两个null.
这是因为如果对象不属于Guice托管, 那么他也无法得到Guice注入.
如果一定要new GuiceObjectDemo()呢? 没关系, 还有另外一种写法可以满足.
1 GuiceObjectDemo demo1 = new GuiceObjectDemo();
2 Guice.createInjector().injectMembers(demo1);
3 System.out.println(demo1.getService());
静态属性注入
调用binder.requestStaticInjection
1 Guice.createInjector(new Module() {
2 @Override
3 public void configure(Binder binder) {
4 binder.requestStaticInjection(GuiceObjectDemo.class);
5 }
6 });
7 System.out.println(GuiceObjectDemo.getService3());
普通属性也可以通过该方法注入, 只要把binder那边改成requestInjection即可.
构造函数注入
1 @Inject
2 public GuiceObjectDemo(TestService service1, TestService service2) {
3 this.service1 = service1;
4 this.service2 = service2;
5 }
构造函数会自动注入多个参数, 因此只要写一个@Inject即可.
如果有多个构造函数, 只能在一个构造函数上加Inject, 不然会报错
has more than one constructor annotated with @Inject
同理Setter注入, 只要在setXX方法上加上@Inject标签即可实现赋值.
动态参数注入
这个稍微麻烦一点, 需要引入guice-assistedinject, 利用FactoryModuleBuilder构造一个factory实行注入.
实际业务场景中, 大部分构造函数的参数是动态从外部传递进来的, 并不是直接new出来的.
1 public class ServiceImpl implements TestService{
2
3 private String member;
4
5 @Inject
6 public ServiceImpl(@Assisted String member) {
7 // 利用Assisted注解, 动态注入参数
8 this.member = member;
9 }
10
11 public void setMember(String member) {
12 this.member = member;
13 }
14
15 @Override
16 public String toString() {
17 return "ServiceImpl Memeber: " + member;
18 }
19 }
20 ---------------------------------------
21 public interface TestService {
22
23 }
24 ---------------------------------------
25 public interface PageFactory {
26
27 ReportPageProvider createReportPage(ResultReport report);
28
29 }
30 ---------------------------------------
31 public class IOCDemo {
32
33 public static void main(String[] args){
34 Module module = new com.fr.third.inject.Module() {
35 @Override
36 public void configure(Binder binder) {
37 binder.install(new FactoryModuleBuilder()
38 .implement(TestService.class, ServiceImpl.class)
39 .build(ImplFactory.class)
40 );
41 }
42 };
43
44 Injector injector = Guice.createInjector(module);
45 ImplFactory factory = injector.getInstance(ImplFactory.class);
46 TestService impl = factory.create("neil123");
47 System.out.println(impl);
48 }
49
50 }
有多个实现类的接口
此时通过上文直接写单个@Inject或者Module都无法实现, 需要引入自定义注解, 或者Names方法.
1 public class GuiceObjectDemo {
2
3 @Inject
4 @Named("A")
5 private TestService service1;
6 @Inject
7 @Named("B")
8 private TestService service2;
9
10 ---------------------------------------
11
12 final GuiceObjectDemo demo1 = new GuiceObjectDemo();
13 Guice.createInjector(new Module() {
14 @Override
15 public void configure(Binder binder) {
16 binder.bind(TestService.class).annotatedWith(Names.named("A")).to(ServiceImplA.class);
17 binder.bind(TestService.class).annotatedWith(Names.named("B")).to(ServiceImplB.class);
18 binder.requestInjection(demo1);
19 }
20 });
21 System.out.println(demo1.getService());
22 System.out.println(demo1.getService2());
如果不用Named注解, 则可以通过自定义注解, 其他写法都一样
1 binder.bind(TestService.class).annotatedWith(ImplA.class).to(ServiceImplA.class);
2 binder.bind(TestService.class).annotatedWith(ImplB.class).to(ServiceImplB.class);
Provider注入
其实就是类似于工厂注入, 对象不是直接new接口的实现类, 而是由工厂提供.
1 public class ServiceFactory implements Provider<TestService> {
2
3 @Override
4 public TestService get() {
5 return new ServiceImpl();
6 }
7
8 }
9
10 ---------------------------------------
11
12 @ProvidedBy(ServiceFactory.class)
13 public interface TestService {
14
15 void test();
16 }
17
18 ---------------------------------------
19
20 GuiceObjectDemo demo = Guice.createInjector().getInstance(GuiceObjectDemo.class);
21 System.out.println(demo.getService());
Scope
可以通过在impl类上加@Singleton来实现单例, 也可在module中管理
1 binder.bind(TestService.class).to(ServiceImpl.class).in(Scopes.SINGLETON);
默认单例模式的对象, 是在第一次使用的时候才初始化, 也可以通过设置asEagerSingleton, 注入到容器后立刻初始化.
1 Injector in = Guice.createInjector(new Module() {
2 @Override
3 public void configure(Binder binder) {
4 // 调用getInstance才初始化impl
5 binder.bind(ServiceImpl.class);
6 // 注入到容器后立刻初始化impl
7 // binder.bind(ServiceImpl.class).asEagerSingleton();
8 }
9 });
10 Thread.sleep(3000);
11 in.getInstance(ServiceImpl.class).test();
到这边就结束了, 通过上面的案例不难看出, , 相比于Spring IOC, Guice是一个非常轻量灵活的注入实现, 0 xml.
- vb中实现最佳按钮效果
- silverlight:wcf双工通讯学习笔记
- Docker容器学习梳理--web管理工具DockerUI部署记录
- Docker容器学习梳理-容器硬盘热扩容
- 检测到Loaderlock的问题
- 权威报告预测比特币在2018年“王位”不保
- Linux下FTP环境部署梳理(vsftpd和proftpd)
- Silverlight如何与JS相互调用
- Docker容器学习梳理--私有仓库Registry使用
- 从插件重构看如何提升测试质量与效率
- 巧用WinRAR+Javascript解决activeX的自动安装问题
- 在网页中实现QQ的屏幕截图功能
- Activity之间传递参数
- linux下rsync和tar增量备份梳理
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法