美文网首页
5.Guice开发实战教程

5.Guice开发实战教程

作者: 洛神灬殇 | 来源:发表于2022-04-08 17:53 被阅读0次
       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,清楚明了的逻辑.

    以下代码实现了一个简单的注入

    Injector ij = Guice.createInjector(new Module() {

            @Override
    
            public void configure(Binder binder) {
    
                binder.bind(TestService.class).to(ServiceImpl.class);
    
            }
    
        });
    

    ij.getInstance(TestService.class).test();

    支持绕过Module, 用默认配置, 直接实例化对象, 不过没啥意义, 除非要用容器做aop
    

    Injector ij2 = Guice.createInjector();

    ij2.getInstance(ServiceImpl.class).test();

    当然也可以使用注解的方式来声明接口的实现类, 然后Injector 从接口中获取对象,

    意义也不大, 因为实际业务中, 接口可能在上层包里, 无法直接调用实现类.

    @ImplementedBy(ServiceImpl.class)

    public interface TestService {

       void test(); 
    

    }

    Injector ij3 = Guice.createInjector();

    ij3.getInstance(TestService.class).test();

    @Inject属性注入

    public class GuiceObjectDemo {

    @Inject

    private TestService service1;

    @Inject

    private TestService service2;

    GuiceObjectDemo demo = Guice.createInjector().getInstance(GuiceObjectDemo.class);

    System.out.println(demo.getService());

    System.out.println(demo.getService2());

    }

      属性注入的时候, 必须通过Guice.createInjector().getInstance(GuiceObjectDemo.class);来获取实现类, 如果直接new的话, 会inject失败, 打印出两个null.
    
     这是因为如果对象不属于Guice托管, 那么他也无法得到Guice注入.
    
     如果一定要new GuiceObjectDemo()呢? 没关系, 还有另外一种写法可以满足.
    

    GuiceObjectDemo demo1 =new GuiceObjectDemo();

    Guice.createInjector().injectMembers(demo1);

    System.out.println(demo1.getService());

    静态属性注入
    调用binder.requestStaticInjection

    Guice.createInjector(new Module() {

            @Override
    
            public void configure(Binder binder) {
    
                binder.requestStaticInjection(GuiceObjectDemo.class);
    
            }
    

    });

    System.out.println(GuiceObjectDemo.getService3());

    普通属性也可以通过该方法注入, 只要把binder那边改成requestInjection即可.
    

    构造函数注入
    @Inject

    public GuiceObjectDemo(TestService service1, TestService service2) {

    this.service1 = service1;
    
    this.service2 = service2;
    

    }

    构造函数会自动注入多个参数, 因此只要写一个@Inject即可.
    
    如果有多个构造函数, 只能在一个构造函数上加Inject, 不然会报错
    

    has more than one constructor annotated with @Inject

    同理Setter注入, 只要在setXX方法上加上@Inject标签即可实现赋值.
    

    动态参数注入
    这个稍微麻烦一点, 需要引入guice-assistedinject, 利用FactoryModuleBuilder构造一个factory实行注入.

    实际业务场景中, 大部分构造函数的参数是动态从外部传递进来的, 并不是直接new出来的.
    
    public class ServiceImpl implements TestService{
    

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

    public interface TestService {

    }


    public interface PageFactory {

     ReportPageProvider createReportPage(ResultReport report);
    

    }

    30 ---------------------------------------

    31 public class IOCDemo {

    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 };

         Injector injector = Guice.createInjector(module);
    
         ImplFactory factory = injector.getInstance(ImplFactory.class);
    
         TestService impl = factory.create("neil123");
    
         System.out.println(impl);
    
     }
    

    }

    有多个实现类的接口
    此时通过上文直接写单个@Inject或者Module都无法实现, 需要引入自定义注解, 或者Names方法.

    1. 项目管理这块缺少量化收益
    
    2. 所有的ROI计算错误:ROI是收益/成本,只看到了收益,没看到结合成本计算ROI
    
    3. 收益点还要多想,总体看收益太低,问问自己:收益那么低,为什么那些大厂还在做这些?一定是有很多未被挖掘出来的收益的;
    

    比如之前做了这些带来的挽回的业务损失等等。。

    public class GuiceObjectDemo {

     @Inject
    
     @Named("A")
    
     private TestService service1;
    
     @Inject
    
     @Named("B")
    
     private TestService service2;
    
        final GuiceObjectDemo demo1 = new GuiceObjectDemo();
    
         Guice.createInjector(new Module() {
    
            @Override
    
             public void configure(Binder binder) {
    
                 binder.bind(TestService.class).annotatedWith(Names.named("A")).to(ServiceImplA.class);
    
                 binder.bind(TestService.class).annotatedWith(Names.named("B")).to(ServiceImplB.class);
    
                 binder.requestInjection(demo1);
    
           }
    

    });

    System.out.println(demo1.getService());

    System.out.println(demo1.getService2());

    如果不用Named注解, 则可以通过自定义注解, 其他写法都一样

    binder.bind(TestService.class).annotatedWith(ImplA.class).to(ServiceImplA.class);

    binder.bind(TestService.class).annotatedWith(ImplB.class).to(ServiceImplB.class);

    Provider注入
    其实就是类似于工厂注入, 对象不是直接new接口的实现类, 而是由工厂提供.

    public class ServiceFactory implements Provider<TestService> {

     @Override
    
     public TestService get() {
    
         return new ServiceImpl();
    
     }
    

    }

    @ProvidedBy(ServiceFactory.class)

    public interface TestService {

     void test();
    

    }

    GuiceObjectDemo demo = Guice.createInjector().getInstance(GuiceObjectDemo.class);

    System.out.println(demo.getService());

    Scope
    可以通过在impl类上加@Singleton来实现单例, 也可在module中管理

    binder.bind(TestService.class).to(ServiceImpl.class).in(Scopes.SINGLETON);

    默认单例模式的对象, 是在第一次使用的时候才初始化, 也可以通过设置asEagerSingleton, 注入到容器后立刻初始化.

    Injector in = Guice.createInjector(new Module() {

             @Override
    
             public void configure(Binder binder) {
    
                 // 调用getInstance才初始化impl
    
                 binder.bind(ServiceImpl.class);
    
                 // 注入到容器后立刻初始化impl
    
             // binder.bind(ServiceImpl.class).asEagerSingleton();
    
             }
    
         });
    
         Thread.sleep(3000);
    
        in.getInstance(ServiceImpl.class).test();
    
     到这边就结束了, 通过上面的案例不难看出, , 相比于Spring IOC, Guice是一个非常轻量灵活的注入实现, 0 xml.

    相关文章

      网友评论

          本文标题:5.Guice开发实战教程

          本文链接:https://www.haomeiwen.com/subject/tpiysrtx.html