首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Guice之IOC教程

Guice之IOC教程

作者头像
用户1216491
发布2018-01-24 16:10:05
2K0
发布2018-01-24 16:10:05
举报
文章被收录于专栏:xdecodexdecode

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.

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-12-16 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Guice
  • Module容器
  • @Inject属性注入
  • 静态属性注入
  • 构造函数注入
  • 动态参数注入
  • 有多个实现类的接口
  • Provider注入 
  • Scope
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档