Guice之IOC教程
Guice
在上一篇博客中, 我们讲解了Spring中的IOC示例与实现, 本文着重介绍Guice注入以及与Spring中的差异.
Guice是Google开发的, 一个轻量级的依赖注入框架, 跟Spring最大的区别在于脱离xml配置,
大量使用Annotation来实现注入, 支持属性, 构造器, setter等多种方式注入对象.
Guice 2.0支持 jdk 1.6, 3.0需要1.7以上, 不然会报错ClassNotFoundException: javax.inject.Provider.
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, 用默认配置, 直接实例化对象,
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即可
同理Setter注入, 只要在setXX方法上加上@Inject标签即可实现赋值.
有多个实现类的接口
此时通过上文直接写单个@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.