• 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.

  • 相关阅读:
    js replaceChild
    js hasChildNodes()指针对元素节点子节点多个的话 true
    js:获取节点相关的 nodeName,nodeType,nodeValue
    js 取值 getElementsByTagName,getElementsByName
    小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-5.HttpClient4.x工具获取使用
    小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-4.微信授权一键登录开发之授权URL获取
    小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-3.微信Oauth2.0交互流程讲解
    小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-2.微信扫一扫功能开发前期准备
    小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-1.数据信息安全--微信授权一键登录功能介绍
    小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_4-3.登录检验JWT实战之封装通用方法
  • 原文地址:https://www.cnblogs.com/xdecode/p/8045292.html
Copyright © 2020-2023  润新知