如果一个接口有多个实现类的情况下,单独的@Inject和Module都不容易区分这种情况。
Service.java还像以前一样,这次我们有了两个实现BlueServiceImpl.java和GreeServiceImpl.java。
BlueServiceImpl.java
public class BlueServiceImpl implements Service{ public void hello() { System.out.println("blue"); } }
GreenServiceImpl.java
public class GreenServiceImpl implements Service{ public void hello() { System.out.println("green"); } }
现在的问题是如何决定什么地方使用BlueServiceImpl.java,什么地方使用GreenServiceImpl.java。@ImplementedService.java已经派不上用场了,它明显只能指定一个实现。
为了区分BlueServiceImpl.java和GreenServiceImpl.java这两种实现,我们定义两个绑定注解Blue.java和Green.java。
Blue.java
import java.lang.annotation.*; import com.google.inject.*; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.PARAMETER}) @BindingAnnotation public @interface Blue { }
Green.java
import java.lang.annotation.*; import com.google.inject.*; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.PARAMETER}) @BindingAnnotation public @interface Green { }
除了名称以外两者一模一样,现在我们看看这一层层的注解都是什么意思。
@Retention(RetentionPolicy.RUNTIME)
runtime告诉我们这个注解可以在java的时候使用反射读取到。
@Target注解告诉我们Blue和Green可以用在field和parameter上面。
来看一下Main.java的内容。
import com.google.inject.*; public class Main { @Inject @Blue private Service blueService; @Inject @Green private Service greenService; public static void main(String[] args) { Main main = Guice.createInjector(new Module() { public void configure(Binder binder) { binder.bind(Service.class).annotatedWith(Blue.class) .to(BlueServiceImpl.class); binder.bind(Service.class).annotatedWith(Green.class) .to(GreenServiceImpl.class); } }).getInstance(Main.class); main.blueService.hello(); main.greenService.hello(); } }
我们还是要先看Module的部分,这里将BlueServiceImpl.class和GreenServiceImpl.class分别绑定到Service.class上。
与之前不同的是,这里增加了附加条件,annotatedWith(Blue.class)的意思是遇到@Blue就把BlueServiceImpl.class注入给Service。它对应的代码是@Inject @Blue private Service blueService;,这样经过guice注入,blueService最后会获得BlueServiceImpl.class类型的实例,最后执行main.blueService.hello()的时候,我们会看到控制台打印出来的“blue”,greenService字段也是相同效果,自己验证吧。
例子:03-01。
重申一遍,懒惰是程序员最大的美德。自定义注解实在太麻烦了,有没有简便一点儿的方法?如果你像我一样懒得自己写新注解,就试用一下guice提供的Named注解吧。
修改后的Main.java内容如下。
import com.google.inject.*; import com.google.inject.name.Named; import static com.google.inject.name.Names.*; public class Main { @Inject @Named("blue") private Service blueService; @Inject @Named("green") private Service greenService; public static void main(String[] args) { Main main = Guice.createInjector(new Module() { public void configure(Binder binder) { binder.bind(Service.class).annotatedWith(named("blue")) .to(BlueServiceImpl.class); binder.bind(Service.class).annotatedWith(named("green")) .to(GreenServiceImpl.class); } }).getInstance(Main.class); main.blueService.hello(); main.greenService.hello(); } }
import static com.google.inject.name.Names.*;部分导入的静态方法,我们实际上只用到了named()。看看Module中的annotatedWith(named("blue")),它对应的是@Inject @Named("blue") private Service blueService;。
通过使用Names.named("blue")和@Named("blue"),我们实现了原来@Blue的功能,这里我们使用指定字符串的值将两者对应起来。以少写代码少犯错的原则来说,这种情况下还是用guice提供的@Named比较好哦。
例子:03-02。