Guice框架-DI(依赖注入基础入门)

所谓的绑定就是将一个接口绑定到具体的类中,这样客户端不用关心具体的实现,而只需要获取相应的接口完成其服务即可。

HelloWorld.java

     public interface HelloWorld {

        String sayHello();

     }

然后是具体的实现,HelloWorldImpl.java

     public class HelloWorldImpl implements HelloWorld {

        @Override

       public String sayHello() {

             return "Hello, world!";

         }

     }

 

写一个测试例子看看,HelloWorldTest.java

   public class HelleWorldTest {

        @Test

       public void testSayHello() {

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

                @Override

                public void configure(Binder binder) {

                  binder.bind(HelloWorld.class).to(HelloWorldImpl.class);

                }

            });

           HelloWorld hw = inj.getInstance(HelloWorld.class);

           Assert.assertEquals(hw.sayHello(), "Hello, world!");

       }

   }

 

这个例子非常简单,通俗的将就是将一个HelloWorldImpl的实例与HelloWorld关联起来,当想Guice获取一个HelloWorld实例的时候,Guice就返回一个HelloWorldImpl的实例,然后我们就可以调用HelloWorld服务的方法了。

自我分析:针对于Factory工厂类的框架整合!

问题(1)HelloWorld是单例的么?测试下。

HelloWorld hw = inj.getInstance(HelloWorld.class); 

Assert.assertEquals(hw.sayHello(), "Hello, world!");

HelloWorld hw2 = inj.getInstance(HelloWorld.class);

System.out.println(hw.hashCode()+"->"+hw2.hashCode());

Assert.assertEquals(hw.hashCode(), hw2.hashCode());

解答(1)测试结果告诉我们,HelloWorld不是单例的,每次都会返回一个新的实例。

问题(2)HelloWorld的实例是HelloWorldImpl么?可以强制转型么?

HelloWorld hw = inj.getInstance(HelloWorld.class);

System.out.println(hw.getClass().getName());

解答(2),

结果输出

cn.imxylz.study.guice.helloworld.HelloWorldImpl,看来确实只是返回了一个正常的实例,并没有做过多的转换和代理。

 

问题(3),如果绑定多个实现到同一个接口上会出现什么情况?

public class HelloWorldImplAgain implements HelloWorld {

    @Override

     public String sayHello() {

        return "Hello world again.";

     }

}

binder.bind(HelloWorld.class).to(HelloWorldImpl.class);

binder.bind(HelloWorld.class).to(HelloWorldImplAgain.class);

 

解答(3),很不幸,Guice目前看起来不允许多个实例绑定到同一个接口上了。

com.google.inject.CreationException: Guice creation errors:

1) A binding to cn.imxylz.study.guice.helloworld.HelloWorld was already configured at cn.imxylz.study.guice.helloworld.HelleWorldTest$1.configure(HelleWorldTest.java:28). 

  at cn.imxylz.study.guice.helloworld.HelleWorldTest$1.configure(HelleWorldTest.java:29)

 

问题(4),可以绑定一个实现类到实现类么?

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

      @Override

       public void configure(Binder binder) {

          binder.bind(HelloWorldImpl.class).to(HelloWorldImpl.class);

       }

  });

HelloWorld hw = inj.getInstance(HelloWorldImpl.class);

System.out.println(hw.sayHello());

 

 

非常不幸,不可以自己绑定到自己。

1) Binding points to itself. 

  at cn.imxylz.study.guice.helloworld.HelleWorldTest$1.configure(HelleWorldTest.java:28)

我们来看看bind的语法。

<T> AnnotatedBindingBuilder<T> bind(Class<T> type);

ScopedBindingBuilder to(Class<? extends T> implementation);

也就是说只能绑定一个类的子类到其本身

。改造下,改用子类替代。

    public class HelloWorldSubImpl extends HelloWorldImpl {

         @Override

         public String sayHello() {

             return "@HelloWorldSubImpl";

         }

    }

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

            @Override

           public void configure(Binder binder) {

               binder.bind(HelloWorldSubImpl.class).to(HelloWorldSubImpl.class);

           }

        });

      HelloWorldImpl hw = inj.getInstance(HelloWorldImpl.class);

      System.out.println(hw.sayHello());

支持子类绑定,这样即使我们将一个实现类发布出去了(尽管不推荐这么做),我们在后期仍然有办法替换实现类。

使用bind有一个好处,由于JAVA 5以上的泛型在编译器就确定了,所以可以帮我们检测出绑定错误的问题,而这个在配置文件中是无法检测出来的。

这样看起来Module像是一个Map,根据一个Key获取其Value,非常简单的逻辑。

问题(5),可以绑定到我们自己构造出来的实例么?

解答(5)当然可以!看下面的例子。

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

             @Override

             public void configure(Binder binder) {

                binder.bind(HelloWorld.class).toInstance(new HelloWorldImpl());

             }

         });

      HelloWorld hw = inj.getInstance(HelloWorld.class);

      System.out.println(hw.sayHello());

问题(6),我不想自己提供逻辑来构造一个对象可以么?

解答(6),可以Guice提供了一个方式(Provider<T>),允许自己提供构造对象的方式。

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

        @Override

        public void configure(Binder binder) {

            binder.bind(HelloWorld.class).toProvider(new Provider<HelloWorld>() {

                @Override

                public HelloWorld get() {

                    return new HelloWorldImpl();

                }

            });

       }

   });

 HelloWorld hw = inj.getInstance(HelloWorld.class);

 System.out.println(hw.sayHello());

问题(7),实现类可以不经过绑定就获取么?比如我想获取HelloWorldImpl的实例而不通过Module绑定么?

解答(7),可以,实际上Guice能够自动寻找实现类。

Injector inj=  Guice.createInjector();

HelloWorld hw = inj.getInstance(HelloWorldImpl.class);

System.out.println(hw.sayHello());

问题(8),可以使用注解方式完成注入么?不想手动关联实现类。

解答(8),好,Guice提供了注解的方式完成关联。我们需要在接口上指明此接口被哪个实现类关联了。

 @ImplementedBy(HelloWorldImpl.class)

   public interface HelloWorld {

         String sayHello();

  }

Injector inj=  Guice.createInjector();

HelloWorld hw = inj.getInstance(HelloWorld.class);

System.out.println(hw.sayHello());

 

事实上对于一个已经被注解的接口我们仍然可以使用Module来关联,这样获取的实例将是Module关联的实例,而不是@ImplementedBy注解关联的实例。这样仍然遵循一个原则,手动优于自动。

问题(9)再回头看问题(1)怎么绑定一个单例?

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

          @Override

          public void configure(Binder binder) {

           binder.bind(HelloWorld.class).to(HelloWorldImplAgain.class).in(Scopes.SINGLETON);

          }

      });

      HelloWorld hw = inj.getInstance(HelloWorld.class);

      HelloWorld hw2 = inj.getInstance(HelloWorld.class);

      System.out.println(hw.hashCode() + "->" + hw2.hashCode());

可以看到现在获取的实例已经是单例的,不再每次请求生成一个新的实例。

事实上Guice提供两种Scope,

com.google.inject.Scopes.SINGLETON和com.google.inject.Scopes.NO_SCOPE,

所谓没有scope即是每次生成一个新的实例。

 

对于自动注入就非常简单了,只需要在实现类加一个Singleton注解即可。

@Singleton

public class HelloWorldImpl implements HelloWorld {

@Override

  public String sayHello() {

    return "Hello, world!";

  }

}

时间: 2024-09-20 16:22:53

Guice框架-DI(依赖注入基础入门)的相关文章

Guice框架-DI(依赖注入之作用域)

本章节继续讨论依赖注入的其他话题,包括作用域(scope,这里有一个与线程绑定的作用域例子).立即初始化(Eagerly Loading Bindings).运行阶段(Stage).选项注入(Optional Injection)等等.     1.3.5 Scope(作用域)   在1.1章节中我们初步了解了对象的单例模式,在Guice中提供了一些常见的作用域,比如对于单例模式有下面两个作用域.         com.google.inject.Scopes.SINGLETON      

Guice框架-DI(依赖注入细节注入)

1.3 多接口实现 1.3.1 接口多实现 如果一个接口有多个实现,这样通过@Inject和Module都难以直接实现,但是这种现象确实是存在的,于是Guice提供了其它注入方式来解决此问题. 比如下面的自定义注解.  public interface Service {      void execute();  }  public class HomeService implements Service {      @Override      public void execute()

Guice框架-DI(依赖注入属性注入)

1.2.1 基本属性注入 首先来看一个例子.Service.java  @ImplementedBy(ServiceImpl.class)   public interface Service {       void execute();  }   ServiceImpl.java  public class ServiceImpl implements Service {     @Override     public void execute() {         System.out

phalapi-进阶篇2(DI依赖注入和单例模式)

phalapi-进阶篇2(DI依赖注入和单例模式) 前言 先在这里感谢phalapi框架创始人@dogstar,为我们提供了这样一个优秀的开源框架. 离上一次更新过去了快两周,在其中编写了一个关于DB分表分库解决大数据量的拓展,有兴趣的童鞋可以了解了解.废话不多说,本小节在于解释一下在PhalApi框架中两个比较好的思想,单例模式和依赖注入. 附上: 官网地址:http://www.phalapi.net/ 开源中国Git地址:http://git.oschina.net/dogstar/Pha

Spring DI[依赖注入]

依赖注入(Dependency Injection,简称DI)意思是由容器或者框架将被调用类注入给调用对象,以此来降低调用对象和被调用类之间的依赖关系. 依赖注入主要有2种不同的实现形式: 1. 构造函数注入(Constructor Injection) 2. 设值注入(Setter Injection) 1.构造函数注入 通过调用类的构造函数,并将被调用类当做参数传递给构造函数,以此实现注入. example: public class UserImpl implements UserDao

java框架spring依赖注入的6种方式

spring中如何给对象的属性复制? 1)通过构造方法2)通过set方法给属性注入值3)p命名空间4)自动转配(了解即可,不推荐使用)5)注解6)通过接口 准备工作(模拟业务方法)Action-->service-->dao 1)UserDao:     p<span style="font-family:Courier New;">ublic class UserDao {           public void save(){              

Android 使用dagger2进行依赖注入(基础篇)

0. 前言 Dagger2是首个使用生成代码实现完整依赖注入的框架,极大减少了使用者的编码负担,本文主要介绍如何使用dagger2进行依赖注入.如果你不还不了解依赖注入,请看这一篇. 1. 简单的依赖注入 首先我们构建一个简单Android应用.我们创建一个UserModel,然后将它显示到TextView中.这里的问题是,在创建UserModel的时候,我们使用了前文所说的hard init.一旦我们的UserModel的创建方式发生了改变(比如需要传入Context对象到构造函数),我们就需

ABP框架的基础配置及依赖注入讲解_基础应用

配置ABP配置是通过在自己模块的PreInitialize方法中来实现的 代码示例如下: public class SimpleTaskSystemModule : AbpModule { public override void PreInitialize() { //在你的应用中添加语言包,这个是英语和作者的土耳其语. Configuration.Localization.Languages.Add(new LanguageInfo("en", "English"

我要造轮子之IoC和依赖注入

1.前言 因为这是我设想要写的一系列文章的第一篇.所以我先说明一下我为什么要重复造轮子. 在这里造轮子的目的不是为了造出比前人更出色的轮子来,而是通过造轮子,学习轮子内部的结构及相关原理.甚至去模仿前人轮子上的优点,吸收这些优点. 这一系列文章初步估计应该包括:IoC和依赖注入.AOP.ORM.Servlet容器(tomcat)等. 2.IoC和依赖注入的概念 Inverse of Control,控制反转. IoC主要功能是依赖关系的转移.应用的本身不负责依赖对象的创建和维护,而是由第三方容器