精华内容
下载资源
问答
  • Google Guice 接口多实现 注入

    千次阅读 2014-05-01 23:29:24
    一个接口都只能绑定到一个具体的实现类上,现在如果在一个调用类中,有多个Hello.java这个接口的属性,需要绑定到不同的实现类上,这如何使用Guice框架来完成注入呢? 这一节我们来说说接口多个实现类的注入方式 ...

    前面几节主要介绍了绑定和注入方式,但是我们看到无论是通过在Module中通过Binder来绑定还是通过@ImplementedBy注解来绑定,一个接口都只能绑定到一个具体的实现类上,现在如果在一个调用类中,有多个Hello.java这个接口的属性,需要绑定到不同的实现类上,这如何使用Guice框架来完成注入呢?

    这一节我们来说说接口多个实现类的注入方式

    (1)首先定义一个接口Hello.java和两个不同的实现类HelloImpl1.java,helloImpl.java

    package guice.di.mutiple;
    
    public interface Hello {
    	//定义一个sayHello方法
    	void satHello() ;
    }
    
    package guice.di.mutiple;
    
    //Hello 的实现类HelloImpl1
    public class HelloImpl1 implements Hello{
    	
    	public void satHello() {
    		System.out.println("HelloImpl1 say Hello!");
    	};
    }
    
    package guice.di.mutiple;
    
    //Hello的具体实现类HelloImpl2
    public class HelloImpl2 implements Hello{
    
    	@Override
    	public void satHello() {
    		System.out.println("HelloImpl2 say Hello!");
    	}
    }
    

    (2)创建一个Hello这个接口的调用者

    package guice.di.mutiple;
    
    import com.google.inject.Inject;
    import com.google.inject.name.Named;
    //将一个接口绑定到多个实现类上
    public class HelloCaller {
    	
    	@Inject
    	@Named("HelloImpl1")
    	private Hello helloImpl1 ;
    	@Inject
    	@Named("HelloImpl2")
    	private Hello helloImpl2 ;
    	
    	public void sayHello1(){
    		helloImpl1.satHello() ;
    	}
    	
    	public void sayHello2(){
    		helloImpl2.satHello() ;
    	}
    }

    (3)创建MyModule来实现一个接口绑定多个实现类

    package guice.di.mutiple;
    
    import com.google.inject.Binder;
    import com.google.inject.Module;
    import com.google.inject.name.Names;
    
    public class MyModule implements Module{
    
    	@Override
    	public void configure(Binder binder) {
    		//通过annotatedWith 中使用Named方法来绑定多个实现类
    		binder.bind(Hello.class).annotatedWith(Names.named("HelloImpl1")).to(HelloImpl1.class) ;
    		binder.bind(Hello.class).annotatedWith(Names.named("HelloImpl2")).to(HelloImpl2.class) ;
    	}
    }
    (4)创建测试程序

    package guice.di.mutiple;
    
    import com.google.inject.Guice;
    import com.google.inject.Injector;
    
    public class Client {
    	
    	public static void main(String[] args) {
    		
    		Injector in = Guice.createInjector(new MyModule()) ;
    		HelloCaller caller = in.getInstance(HelloCaller.class) ;
    		
    		caller.sayHello1() ;
    		caller.sayHello2() ;
    	}
    }
    

    输出结果:

    HelloImpl1 say Hello!
    HelloImpl2 say Hello!

    本文介绍通过使用@Named注解来完成一个接口(父类)绑定多个实现类(子类)的方式。

    展开全文
  • Guice依赖注入(接口多实现)

    万次阅读 2020-09-27 20:47:48
    本教程主要详细讲解Guice依赖注入中的特性接口多实现,一般使用到guice的框架的插件机制都是基于该方式实现。 基础环境 技术 版本 Java 1.8+ Guice 4.2.3 初始化项目 初始化项目 mvn archetype:...

    本教程主要详细讲解Guice依赖注入中的特性接口多实现,一般使用到guice的框架的插件机制都是基于该方式实现。

    基础环境


    技术版本
    Java1.8+
    Guice4.2.3

    初始化项目


    • 初始化项目
    mvn archetype:generate -DgroupId=com.edurt.sli.guice -DartifactId=guice-binder-multiple -DarchetypeArtifactId=maven-archetype-quickstart -Dversion=1.0.0 -DinteractiveMode=false
    
    • 修改pom.xml增加Guice依赖
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
        <parent>
            <artifactId>learn-integration-guice</artifactId>
            <groupId>com.edurt.sli.guice</groupId>
            <version>1.0.0</version>
        </parent>
    
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>guice-binder-multiple</artifactId>
        <name>Guice依赖注入(接口多实现)</name>
    
        <properties>
            <system.java.version>1.8</system.java.version>
            <guice.version>4.2.3</guice.version>
            <lombok.version>1.18.2</lombok.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>com.google.inject</groupId>
                <artifactId>guice</artifactId>
                <version>${guice.version}</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>${plugin.maven.compiler.version}</version>
                    <configuration>
                        <source>${system.java.version}</source>
                        <target>${system.java.version}</target>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    </project>
    

    guice: guice就是我们核心要使用的依赖

    接口多实现注入


    如果一个接口有多个实现,如果单单通过@InjectModule都难以直接实现,但多实现是经常会出现的,Guice提供了其它注入方式来解决此问题。

    • 创建com.edurt.sli.guice.multiple文件夹,并在该文件夹下创建Service接口文件,用于添加我们需要测试的函数
    package com.edurt.sli.guice.multiple;
    
    public interface Service {
    
        void print(String source);
    
    }
    
    • 创建Service接口的实现类JavaServiceGuiceService,用于实现接口中的方法,代码如下
    package com.edurt.sli.guice.multiple;
    
    public class JavaService implements Service {
        
        @Override
        public void print(String source) {
            System.out.println("Java Service " + source);
        }
        
    }
    
    package com.edurt.sli.guice.multiple;
    
    public class GuiceService implements Service {
        
        @Override
        public void print(String source) {
            System.out.println("Guice Service " + source);
        }
        
    }
    
    • 创建GuiceJava注解类,用于提供guice框架标识
    package com.edurt.sli.guice.multiple;
    
    import com.google.inject.BindingAnnotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD, ElementType.PARAMETER})
    @BindingAnnotation
    public @interface Guice {
    }
    
    package com.edurt.sli.guice.multiple;
    
    import com.google.inject.BindingAnnotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD, ElementType.PARAMETER})
    @BindingAnnotation
    public @interface Java {
    }
    
    • 创建用于测试注入的应用类Application,代码如下
    package com.edurt.sli.guice.multiple;
    
    import com.google.inject.Guice;
    import com.google.inject.Inject;
    
    public class Application {
    
        @Inject
        @Java
        public Service java;
    
        @Inject
        @com.edurt.sli.guice.multiple.Guice
        public Service guice;
    
        public static void main(String[] args) {
            Application application = Guice.createInjector(binder -> {
                binder.bind(Service.class).annotatedWith(Java.class).to(JavaService.class);
                binder.bind(Service.class).annotatedWith(com.edurt.sli.guice.multiple.Guice.class).to(GuiceService.class);
            }).getInstance(Application.class);
            application.guice.print("sss");
            application.java.print("sss");
        }
    
    }
    

    我们运行程序输出

    Guice Service sss
    Java Service sss
    

    我们注意看binder的配置中,我们将注解与实际的实现类绑定到了一起,这样就实现了绑定多接口实现的功能。

    注意:在本次程序中我们使用的是lambda表达式进行的代码编程,需要jdk1.8及以上版本

    静态代码注入


    我们如果需要进行静态代码注入服务该怎么写呢?我们参照以前讲解的Guice依赖注入(构造函数注入)资源中,我们创建一个ApplicationStatic类进行static的注入,代码如下

    package com.edurt.sli.guice.multiple;
    
    import com.google.inject.Inject;
    
    public class ApplicationStatic {
    
        @Inject
        @Java
        public static Service java;
    
        @Inject
        @com.edurt.sli.guice.multiple.Guice
        public static Service guice;
    
        public static void main(String[] args) {
            com.google.inject.Guice.createInjector(binder -> {
                binder.bind(Service.class).annotatedWith(Java.class).to(JavaService.class);
                binder.bind(Service.class).annotatedWith(com.edurt.sli.guice.multiple.Guice.class).to(GuiceService.class);
                binder.requestStaticInjection(ApplicationStatic.class);
            });
            ApplicationStatic.guice.print("sss");
            ApplicationStatic.java.print("sss");
        }
    
    }
    

    我们只需要在binder阶段将我们的主类注入到guice容器中,也就是我们看到的binder.requestStaticInjection(ApplicationStatic.class);代码,运行程序输出以下内容

    Guice Service sss
    Java Service sss
    

    属性绑定多接口


    先看一下多接口绑定的示例

    package com.edurt.sli.guice.multiple;
    
    import com.google.inject.Guice;
    import com.google.inject.Inject;
    
    public class ApplicationMultipleProperty {
    
        @Inject
        public Service java;
    
        @Inject
        public Service guice;
    
        public static void main(String[] args) {
            ApplicationMultipleProperty application = Guice.createInjector(binder -> {
                binder.bind(Service.class).annotatedWith(Java.class).to(JavaService.class);
                binder.bind(Service.class).annotatedWith(com.edurt.sli.guice.multiple.Guice.class).to(GuiceService.class);
            }).getInstance(ApplicationMultipleProperty.class);
            application.guice.print("sss");
            application.java.print("sss");
        }
    
    }
    

    运行以上代码,就会出现以下错误

    Exception in thread "main" com.google.inject.ConfigurationException: Guice configuration errors:
    
    1) No implementation for com.edurt.sli.guice.multiple.Service was bound.
      Did you mean?
        * com.edurt.sli.guice.multiple.Service annotated with interface com.edurt.sli.guice.multiple.Java
        * com.edurt.sli.guice.multiple.Service annotated with interface com.edurt.sli.guice.multiple.Guice
      while locating com.edurt.sli.guice.multiple.Service
        for field at com.edurt.sli.guice.multiple.Application.guice(Application.java:6)
      while locating com.edurt.sli.guice.multiple.Application
    
    2) No implementation for com.edurt.sli.guice.multiple.Service was bound.
      Did you mean?
        * com.edurt.sli.guice.multiple.Service annotated with interface com.edurt.sli.guice.multiple.Java
        * com.edurt.sli.guice.multiple.Service annotated with interface com.edurt.sli.guice.multiple.Guice
      while locating com.edurt.sli.guice.multiple.Service
        for field at com.edurt.sli.guice.multiple.Application.java(Application.java:6)
      while locating com.edurt.sli.guice.multiple.Application
    
    2 errors
    	at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1120)
    	at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1078)
    	at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1131)
    	at com.edurt.sli.guice.multiple.Application.main(Application.java:18)
    

    这是因为我们使用了属性绑定了多接口实现,导致guice无法识别具体是哪个实现类,不过guice是强大的这种问题也被考虑到了,只需要使用@Named模板生成注解即可解决,我们姜代码修改为以下内容

    package com.edurt.sli.guice.multiple;
    
    import com.google.inject.Guice;
    import com.google.inject.Inject;
    import com.google.inject.name.Named;
    import com.google.inject.name.Names;
    
    public class ApplicationMultipleProperty {
    
        @Inject
        @Named("Java")
        public Service java;
    
        @Inject
        @Named("Guice")
        public Service guice;
    
        public static void main(String[] args) {
            ApplicationMultipleProperty application = Guice.createInjector(binder -> {
                binder.bind(Service.class).annotatedWith(Names.named("Java")).to(JavaService.class);
                binder.bind(Service.class).annotatedWith(Names.named("Guice")).to(GuiceService.class);
            }).getInstance(ApplicationMultipleProperty.class);
            application.guice.print("sss");
            application.java.print("sss");
        }
    
    }
    

    运行程序后,输出以下结果

    Guice Service sss
    Java Service sss
    

    这个示例也很好理解,其实我们只是做了两步操作

    • 在绑定实现的时候使用annotatedWith(Names.named("Java"))进行对该服务实现做名称标志
    • 在需要使用服务实现的地方使用@Named("Java")进行服务的引用即可

    打包文件部署


    • 打包数据
    mvn clean package -Dmaven.test.skip=true -X
    

    运行打包后的文件即可

    java -jar target/guice-binder-multiple-1.0.0.jar
    

    源码地址


    展开全文
  • 之前某个Jar里写了一个接口,然后该接口有几个不同的实现类,然后项目中使用了Guice来管理依赖并进行注入,因此对待这个情况就采用Guice的BindingAnnotations的方式来进行注入,但是在运行时Guice...

        今天被自己之前遗留的问题坑了一把,还是写篇日志记录一下吧。

        之前某个Jar里写了一个接口,然后该接口有几个不同的实现类,然后项目中使用了Guice来管理依赖并进行注入,因此对待这个情况就采用Guice的BindingAnnotations的方式来进行注入,但是在运行时Guice会抛出无法正确注入,找到实现类的错误提示,很是让人恼火。经过仔细观察Log发现问题就出在这个接口上。

        这个接口和Guice的例子唯一不同的地方就在于其是一个泛型接口,我们来举例说明这个问题:

    public interface IFoo<T> {
        public  T foo();
    }
    

        可以看到上面的泛型参数决定了foo函数的返回值,其实现类如下:

    public static  class FooA implements IFoo<Integer> {
    
        @Override
        public Integer foo() {
            return 1;
        }
    }
    
    public static class FooB implements IFoo<String> {
    
    
        @Override
        public String foo() {
            return "hello";
        }
    }
    

        然后在创建一个Module类来注册这些实现类:

        public static class FooModule extends AbstractModule {
    
            @Override
            protected void configure() {
                bind(IFoo.class).annotatedWith(Names.named("A")).to(FooA.class);
                bind(IFoo.class).annotatedWith(Names.named("B")).to(FooB.class);
    
            }
    	}
    

        再写一个用来使用这些接口的测试类:

        @Singleton
        public static class TestFoo {
            @Named("A")
            @Inject
            private IFoo<Integer> fooA;
    
            @Named("B")
            @Inject()
            private IFoo<String> fooB;
    
    
    
            public void t() {
               Object a = fooA.foo();
               Object b = fooB.foo();
               System.out.println("A:" + a);
               System.out.println("B:" + b);
            }
        }    
        
        public static void main(String[] args) {
            Injector injector = Guice.createInjector(new FooModule());
            TestFoo f = injector.getInstance(TestFoo.class);
            f.t();
    
        }	
    

        当运行时我们会发现Guice会抛出如下运行时错误:

    Exception in thread "main" com.google.inject.ConfigurationException: Guice configuration errors:
    
    1) No implementation for com.aceclarks.papaya.storage.test.TestGuiceNamedBind$IFoo<java.lang.Integer> annotated with @com.google.inject.name.Named(value=A) was bound.
      while locating com.aceclarks.papaya.storage.test.TestGuiceNamedBind$IFoo<java.lang.Integer> annotated with @com.google.inject.name.Named(value=A)
        for field at com.aceclarks.papaya.storage.test.TestGuiceNamedBind$TestFoo.fooA(TestGuiceNamedBind.java:57)
      while locating com.aceclarks.papaya.storage.test.TestGuiceNamedBind$TestFoo
    
    2) No implementation for com.aceclarks.papaya.storage.test.TestGuiceNamedBind$IFoo<java.lang.String> annotated with @com.google.inject.name.Named(value=B) was bound.
      while locating com.aceclarks.papaya.storage.test.TestGuiceNamedBind$IFoo<java.lang.String> annotated with @com.google.inject.name.Named(value=B)
        for field at com.aceclarks.papaya.storage.test.TestGuiceNamedBind$TestFoo.fooB(TestGuiceNamedBind.java:57)
      while locating com.aceclarks.papaya.storage.test.TestGuiceNamedBind$TestFoo
    
    2 errors
    	at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1004)
    	at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:961)
    	at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1013)
    	at com.aceclarks.papaya.storage.test.TestGuiceNamedBind.main(TestGuiceNamedBind.java:78)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:606)
    	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
    

        其实这里发生的原因就是在于我们在FooModuleconfigure里注册的是绑定到接口IFoo的关联关系,但是Guice在运行时在TestFoo里的两个IFoo接口成员的声明是带有泛型参数的,Guice在注入时,没有找到对应的实现类,因此就会抛出如上的运行时异常,这个问题解决方法有两个:

    • 第一个方法是,在TestFoo的IFoo接口成员声明时,去掉泛型参数,这样Guice在运行时查找匹配的实现时就会按照IFoo的实现类去查找,而不是按照IFoo<Integer> 或 IFoo<String> 这样的带有泛型参数的接口去查找

    • 第二个方法是,在FooModule中configure函数里,在bind的时候使用TypeLiteral类来在注册的时候保持泛型参数信息进行注册,这样就可以保证注册的信息里是以带有泛型参数的接口注册的,代码例子如下:

        public static class FooModule extends AbstractModule {
      
            @Override
            protected void configure() {
                bind(new TypeLiteral<IFoo<Integer>>() {}).annotatedWith(Names.named("A")).to(FooA.class);
                bind(new TypeLiteral<IFoo<String>>() {}).annotatedWith(Names.named("B")).to(FooB.class);
      
            }
        }
      

    转载于:https://my.oschina.net/pigsoldier/blog/223215

    展开全文
  • guice

    2019-03-06 11:38:00
    作为示例,我们使用 BillingService,它依赖于 CreditCardProcessor 和 TransactionLog 两个接口。接下来我们看看如何使用Guice: class BillingService { private final CreditCardProcess...

    Guice简介
    Guice 简介,本文中的内容也是参考该文档完成,如有不一致,以该文为准。

    快速上手
    作为示例,我们使用 BillingService,它依赖于 CreditCardProcessor 和 TransactionLog 两个接口。接下来我们看看如何使用Guice:

    class BillingService {
      private final CreditCardProcessor processor;
      private final TransactionLog transactionLog;
    
      @Inject
      BillingService(CreditCardProcessor processor, 
          TransactionLog transactionLog) {
        this.processor = processor;
        this.transactionLog = transactionLog;
      }
    
      public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
        ...
      }
    }



    我们将会把 PaypalCreditCardProcessor 和 DatabaseTransactionLog 注入BillingService。 
    Guice 使用 bindings 将类型和实现对应起来。module 是特定的 bindings 的集合。

    
    public class BillingModule extends AbstractModule {
    
      @Override 
      protected void configure() {
    
          /**
           *这是告诉Guice,当遇到一个对象依赖于TransactionLog时,
           *将DatabaseTransactionLog注入
           */
          bind(TransactionLog.class).to(DatabaseTransactionLog.class);
    
          /**同上*/
          bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class);
      }
    }


    现在可以编写main方法了:

     

    public static void main(String[] args) {
        /*
         * Guice.createInjector() takes your Modules, and returns a new Injector
         * instance. Most applications will call this method exactly once, in their
         * main() method.
         */
        Injector injector = Guice.createInjector(new BillingModule());
    
        /*
         * Now that we've got the injector, we can build objects.
         */
        BillingService billingService = injector.getInstance(BillingService.class);
        ...
      }


    大功告成!!!

    Bindings
    injector 的职责是确定系统中需要构造哪些对象,解析依赖,装配对象(将被依赖的对象注入依赖的对象)。那么如何指定依赖的解析方式,答案是使用 bindings 配置你的 injector

    创建bindings
    继承 AbstractModule 重写 configure 方法。在该方法中调用 bind() 便创建了一个binding。完成module之后,调用 Guice.createInjector(),将module作为参数传入,便可获得一个injector对象。

    Linked Bindings
    Linked bindings 将一个实现绑定到一个类型。 
    下面例子将 DatabaseTransactionLog 绑定到接口 TransactionLog



     

    public class BillingModule extends AbstractModule {
      @Override 
      protected void configure() {
        bind(TransactionLog.class).to(DatabaseTransactionLog.class);
      }
    }


    绑定之后,当你调用 injector.getInstance(TransactionLog.class) 或当injector遇到一个对象依赖与 TransactionLog,它便会使用 DatabaseTransactionLog。链接可以建立于接口和其实现类,或者子类和父类之间。Linked bindings 可以链式使用。


     

    public class BillingModule extends AbstractModule {
      @Override 
      protected void configure() {
        bind(TransactionLog.class).to(DatabaseTransactionLog.class);
        bind(DatabaseTransactionLog.class).to(MySqlDatabaseTransactionLog.class);
      }
    }


    在这种情况下,当一个对象依赖于 TransactionLog,injector将会返回一个 MySqlDatabaseTransactionLog.

    BindingAnnotations
    Binding Annotations
    有时候,你想要给特定的类型绑定多个实现。例如,你想给 CreditCardProcessor同时绑定 PaypalCreditCardProcessor 和 CheckoutCreditCardProcessor 两个实现. Guice 通过binding annotation满足上述需求。注解和类型共同确定了一个唯一的binding。 在这儿,注解和类型构成了Key。

    首先我们定义一个注解:

     

    import com.google.inject.BindingAnnotation;
    import java.lang.annotation.Target;
    import java.lang.annotation.Retention;
    import static java.lang.annotation.RetentionPolicy.RUNTIME;
    import static java.lang.annotation.ElementType.PARAMETER;
    import static java.lang.annotation.ElementType.FIELD;
    import static java.lang.annotation.ElementType.METHOD;
    
    @BindingAnnotation 
    @Target({ FIELD, PARAMETER, METHOD }) 
    @Retention(RUNTIME)
    public @interface PayPal {}


    然后使用我们定义的注解标示需要注入的类型。

     

    public class RealBillingService implements BillingService {
    
      @Inject
      public RealBillingService(@PayPal CreditCardProcessor processor,
          TransactionLog transactionLog) {
        ...
      }


    最后我们还需要创建相应的binding。


     

    bind(CreditCardProcessor.class)
            .annotatedWith(PayPal.class)
            .to(PayPalCreditCardProcessor.class);


    @Named
    也并不是必须创建自己的注解,Guice提供了一个内建的注解@Named。用法如下:
     

    public class RealBillingService implements BillingService {
    
      @Inject
      public RealBillingService(@Named("Checkout") CreditCardProcessor processor,
          TransactionLog transactionLog) {
        ...
      }
    
    bind(CreditCardProcessor.class)
            .annotatedWith(Names.named("Checkout"))
            .to(CheckoutCreditCardProcessor.class);


    因为编译器不能对String类型进行检查,所以不建议使用@Named
     

    Instance Bindings
    你可以将一个特定类型的实例绑定到该类型。
    
    bind(String.class)
            .annotatedWith(Names.named("JDBC URL"))
            .toInstance("jdbc:mysql://localhost/pizza");
    bind(Integer.class)
            .annotatedWith(Names.named("login timeout seconds"))
            .toInstance(10);


    尽量避免给创建起来比较复杂的对象使用 .toInstance 方法,那样会导致应用启动比较慢。可以使用 @Provides 代替该方法。

    Provides Methods
    当你需要编写创建对象的代码,使用 @Provides 方法。该方法只能定义在module中。并且需要使用 @Provides 修饰。他的返回值是一个对象。当Injector需要某个类型的实例时,便会调用相应的@Provides 方法。
     

    public class BillingModule extends AbstractModule {
      @Override
      protected void configure() {
        ...
      }
    
      @Provides
      TransactionLog provideTransactionLog() {
        DatabaseTransactionLog transactionLog = new DatabaseTransactionLog();
        transactionLog.setJdbcUrl("jdbc:mysql://localhost/pizza");
        transactionLog.setThreadPoolSize(30);
        return transactionLog;
      }
    }


    如果 @Provides 方法有binding annotation ,比如@Paypal 或者 @Named("Checkout"),Guice 也是可以的。所有的被依赖对象以参数形式传入该方法即可。


     

    @Provides @PayPal
      CreditCardProcessor providePayPalCreditCardProcessor(
          @Named("PayPal API key") String apiKey) {
        PayPalCreditCardProcessor processor = new PayPalCreditCardProcessor();
        processor.setApiKey(apiKey);
        return processor;
      }


    需要注意的是, Guice不允许 @Provides 方法抛出异常。

    Provider Bindings
    当 @Provides 方法比较复杂时,你也许会考虑将该方法转移到一个单独的类中。Provider类继承Guice的 Provider 接口。 Provider 接口定义如下:


     

    public interface Provider<T> {
      T get();
    }


    我们的Provider实现类有自己的依赖,所有的依赖是通过被@Inject 修饰的构造函数接收的。
     

    public class DatabaseTransactionLogProvider implements Provider<TransactionLog> {
      private final Connection connection;
    
      @Inject
      public DatabaseTransactionLogProvider(Connection connection) {
        this.connection = connection;
      }
    
      public TransactionLog get() {
        DatabaseTransactionLog transactionLog = new DatabaseTransactionLog();
        transactionLog.setConnection(connection);
        return transactionLog;
      }
    }


    绑定


     

    public class BillingModule extends AbstractModule {
      @Override
      protected void configure() {
        bind(TransactionLog.class)
            .toProvider(DatabaseTransactionLogProvider.class);
      }


    Untargeted Bindings
    一些情况下,你需要创建bindings,但是却不能指定具体的实现。这个对于被@ImplementedBy 或者 @ProvidedBy 修饰的具体类或者类型特别有用。An untargetted binding informs the injector about a type, so it may prepare dependencies eagerly. Untargetted bindings have no to clause, like so:

    bind(MyConcreteClass.class);
    bind(AnotherConcreteClass.class).in(Singleton.class);

     
    当指定binding annotation时,必须加上绑定的目标。


     

    bind(MyConcreteClass.class)
            .annotatedWith(Names.named("foo"))
            .to(MyConcreteClass.class);
    bind(AnotherConcreteClass.class)
            .annotatedWith(Names.named("foo"))
            .to(AnotherConcreteClass.class)
            .in(Singleton.class);


    Constructor Bindings
    有时候, 我们需要绑定一个类型到任意的的构造函数。以下情况会有这种需求:@Inject 注解无法被应用到目标构造函数。或者该类型是一个第三方类。或者该类型中有多个构造函数参与依赖注入。 
    针对这个,Guice 有 @toConstructor() 类型的绑定方式。

     

    public class BillingModule extends AbstractModule {
      @Override 
      protected void configure() {
        try {
          bind(TransactionLog.class).toConstructor(
              DatabaseTransactionLog.class.getConstructor(DatabaseConnection.class));
        } catch (NoSuchMethodException e) {
          addError(e);
        }
      }
    }


    JustInTimeBindings
    Just-in-time Bindings
    当Injector需要一个类型的实例的时候,它需要一个binding。 如果这个binding在一个module中被创建,那么这个binding是显式binding,此时injector在每次需要该类型实例时,都使用该实例。但是如果Injector需要一个类型的实例,但是这个类型并没有对应的显式binding。此时injector会尝试创建一个Just-in-time binding。也叫JIT binding或者隐式binding。

    合格的构造函数
    Guice会使用具体类型的可注入构造函数创建binding。可注入构造函数需要是非private,无参数的或者该构造函数被 @Inject 修饰。
     

    public class PayPalCreditCardProcessor implements CreditCardProcessor {
      private final String apiKey;
    
      @Inject
      public PayPalCreditCardProcessor(@Named("PayPal API key") String apiKey) {
        this.apiKey = apiKey;
      }


    @ImplementedBy
    告诉injector,该类型的默认实现类。

     

    @ImplementedBy(PayPalCreditCardProcessor.class)
    public interface CreditCardProcessor {
      ChargeResult charge(String amount, CreditCard creditCard)
          throws UnreachableException;
    }


    上述代码和一下代码是等价的:

        bind(CreditCardProcessor.class).to(PayPalCreditCardProcessor.class);
     
    如果某个类型同时使用 bind() 和 @ImplementedBy,bind() 会生效。

    @ProvidedBy
    告诉Injector,产生该类型的Provider类


     

    @ProvidedBy(DatabaseTransactionLogProvider.class)
    public interface TransactionLog {
      void logConnectException(UnreachableException e);
      void logChargeResult(ChargeResult result);
    }


    上述代码等价于:

    bind(TransactionLog.class)
            .toProvider(DatabaseTransactionLogProvider.class);
     
    如果同时使用 @ProvidedBy 和 bind() , bind() 会生效。

    Scopes
    默认情况下,Guice 每次都会返回一个新创建的对象。不过这也是可以配置的,以便于我们重用实例。

    配置Scopes
    Guice 使用注解标示Scope。例如:

    @Singleton
    public class InMemoryTransactionLog implements TransactionLog {
      /* everything here should be threadsafe! */
    }

    @Provides @Singleton
    TransactionLog provideTransactionLog() {
      ...
    }
     
    上例中,@Singleton 标示该类型只能有一个实例。并且是线程安全的。

    Scope也可以通过代码来配置:

    bind(TransactionLog.class).to(InMemoryTransactionLog.class).in(Singleton.class);
     
    如果某个类型已经被注解标注了scope,同时还使用bind() 方法配置了scope,那么后者生效。如果一个类型已经被注解配置了scope而你不想那样,你可以使用 bind() 覆盖。

    预加载的单例
    bind(TransactionLog.class).to(InMemoryTransactionLog.class).asEagerSingleton();
     
    Injections
    构造函数注入
    这种情况下,需要用 @Inject 标注构造函数。构造函数同时需要将所依赖的类型作为其参数。通常情况下,都是将传入的参数复制给类的final成员。

    public class RealBillingService implements BillingService {
      private final CreditCardProcessor processorProvider;
      private final TransactionLog transactionLogProvider;

      @Inject
      public RealBillingService(CreditCardProcessor processorProvider,
          TransactionLog transactionLogProvider) {
        this.processorProvider = processorProvider;
        this.transactionLogProvider = transactionLogProvider;
      }
     
    如果没有 @Inject 标注的构造函数,Guice 会使用共有的无参构造函数(如果存在)。

    方法注入
    这种情况下,需要使用@Inject 标注方法,该方法的参数为需要注入的类型。

    public class PayPalCreditCardProcessor implements CreditCardProcessor {

      private static final String DEFAULT_API_KEY = "development-use-only";

      private String apiKey = DEFAULT_API_KEY;

      @Inject
      public void setApiKey(@Named("PayPal API key") String apiKey) {
        this.apiKey = apiKey;
      }
     
    字段注入
    这种情况下,需要使用 @Inject 标注字段。

    public class DatabaseTransactionLogProvider implements Provider<TransactionLog> {
      @Inject Connection connection;

      public TransactionLog get() {
        return new DatabaseTransactionLog(connection);
      }
    }
     
    可选的注入
    有时候,我们的依赖项不是必须的,如果系统中存在依赖项则注入,如果不存在,也不强制要求注入。这种情况在方法注入和字段注入中都是适用的。 启用可选注入,只需要使用 @Inejct(optional=true) 标注字段或方法即可。

    public class PayPalCreditCardProcessor implements CreditCardProcessor {
      private static final String SANDBOX_API_KEY = "development-use-only";

      private String apiKey = SANDBOX_API_KEY;

      @Inject(optional=true)
      public void setApiKey(@Named("PayPal API key") String apiKey) {
        this.apiKey = apiKey;
      }
     
    不过,如果混用可选注入和Just-in-time bindings,可能会产生奇怪的接口。例如:

    @Inject(optional=true) Date launchDate;
     
    上面代码中的date总是会被成功注入即使没有为他创建对应的显示binding,因为它有无参构造函数,Guice会为他创建Just-in-time bindings。

    On-demand注入
    方法和字段注入可以用来初始化一个现存的实例。我们可以使用Injector.injectMember()API:

    public static void main(String[] args) {
        Injector injector = Guice.createInjector(...);

        CreditCardProcessor creditCardProcessor = new PayPalCreditCardProcessor();
        injector.injectMembers(creditCardProcessor);
     
    AOP
    Guice 支持方法拦截器。这里直接看一个实例: 
    假如我们需要禁止在周末调用特定方法

    为了标注我们在周末禁止调用的方法,我们定义一个注解类型:

    @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD)
    @interface NotOnWeekends {}
     
    然后使用该注解标注我们方法

    public class RealBillingService implements BillingService {

      @NotOnWeekends
      public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
        ...
      }
    }
     现在我们定义我们的拦截器,我们的拦截器需要实现org.aopalliance.intercept.MethodInterceptor 接口。

    public class WeekendBlocker implements MethodInterceptor {
      public Object invoke(MethodInvocation invocation) throws Throwable {
        Calendar today = new GregorianCalendar();
        if (today.getDisplayName(DAY_OF_WEEK, LONG, ENGLISH).startsWith("S")) {
          throw new IllegalStateException(
              invocation.getMethod().getName() + " not allowed on weekends!");
        }
        return invocation.proceed();
      }
    }
     
    然后配置我们的拦截器

    public class NotOnWeekendsModule extends AbstractModule {
      protected void configure() {
        /**在这里,我们匹配所有的类,但是只匹配类中有NotOnWeekends的方法*/
        bindInterceptor(Matchers.any(), Matchers.annotatedWith(NotOnWeekends.class), 
            new WeekendBlocker());
      }
    }
     
    所有工作就完成了。

    注入拦截器
    如果需要注入拦截器,使用 `requestInjection` API

    public class NotOnWeekendsModule extends AbstractModule {
      protected void configure() {
        WeekendBlocker weekendBlocker = new WeekendBlocker();
        requestInjection(weekendBlocker);
        bindInterceptor(Matchers.any(), Matchers.annotatedWith(NotOnWeekends.class), 
           weekendBlocker);
      }
    }
     
    另外一种方式是使用 `Binder.getProvider`,将依赖的内容传入拦截器的构造函数。

    public class NotOnWeekendsModule extends AbstractModule {
      protected void configure() {
        bindInterceptor(any(),
                        annotatedWith(NotOnWeekends.class),
                        new WeekendBlocker(getProvider(Calendar.class)));
      }
    }
     
    END
     

    展开全文
  • Guice

    2019-01-09 16:05:23
    Guice 的工作原理: Guice:整个框架的门面 Injector:一个依赖的...Binder:一个接口和实现的绑定 Module:一组 Binder Provider:bean 的提供者 Key:Binder 中对应一个 Provider Scope:Provider 的作用域 ...
  • GUICE

    2015-07-27 09:45:00
    本文通过范例简单地介绍Google Guice的使用,通过下面的范例我们可以知道,Google Guice的使用非常简单。 Google Guice需要使用JDK1.5以上java环境。 下载Google Guice之后,有以下几个文件: Java代码 ...
  • Google Guice的Binder接口

    2008-03-19 15:54:23
    三个bind方法/*** Creates a binding to a key.*/LinkedBindingBuilder bind(Key key); /*** Creates a binding to a type.*/...
  • 1、接口/* * Creation : 2015年6月30日 */ package com.guice.InterfaceManyImpl;public interface Service { public void execute(); } 2、两个实现类 package com.guice.InterfaceManyImpl;public class One...
  • Hello Guice

    2016-09-22 15:03:01
    HelloGuicepackage cn.jiahaixin.guice.hello;public interface HelloGuice {public void sayHello(); }HelloGuiceImplpackage cn.jiahaixin.guice.hello;public class HelloGuiceImpl implements HelloGuice { @O
  • 为何guice

    2018-11-01 17:56:00
    Guice是谷歌推出的一个轻量级依赖注入框架,帮助我们解决Java项目中的依赖注入问题。如果只想在项目中使用依赖注入,这时候我们可以考虑使用Guice,不需要使用Spring那个庞然大物。详细信息可以直接查看Guice文档。 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,724
精华内容 1,889
关键字:

guice接口