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

基础环境


技术 版本
Java 1.8+
Guice 4.2.3

初始化项目


  • 初始化项目
  1. 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依赖
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>learn-integration-guice</artifactId>
  7. <groupId>com.edurt.sli.guice</groupId>
  8. <version>1.0.0</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <artifactId>guice-binder-multiple</artifactId>
  12. <name>Guice依赖注入(接口多实现)</name>
  13. <properties>
  14. <system.java.version>1.8</system.java.version>
  15. <guice.version>4.2.3</guice.version>
  16. <lombok.version>1.18.2</lombok.version>
  17. </properties>
  18. <dependencies>
  19. <dependency>
  20. <groupId>com.google.inject</groupId>
  21. <artifactId>guice</artifactId>
  22. <version>${guice.version}</version>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.projectlombok</groupId>
  26. <artifactId>lombok</artifactId>
  27. <version>${lombok.version}</version>
  28. </dependency>
  29. </dependencies>
  30. <build>
  31. <plugins>
  32. <plugin>
  33. <groupId>org.apache.maven.plugins</groupId>
  34. <artifactId>maven-compiler-plugin</artifactId>
  35. <version>${plugin.maven.compiler.version}</version>
  36. <configuration>
  37. <source>${system.java.version}</source>
  38. <target>${system.java.version}</target>
  39. </configuration>
  40. </plugin>
  41. </plugins>
  42. </build>
  43. </project>

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

接口多实现注入


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

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

我们运行程序输出

  1. Guice Service sss
  2. Java Service sss

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

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

静态代码注入


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

  1. package com.edurt.sli.guice.multiple;
  2. import com.google.inject.Inject;
  3. public class ApplicationStatic {
  4. @Inject
  5. @Java
  6. public static Service java;
  7. @Inject
  8. @com.edurt.sli.guice.multiple.Guice
  9. public static Service guice;
  10. public static void main(String[] args) {
  11. com.google.inject.Guice.createInjector(binder -> {
  12. binder.bind(Service.class).annotatedWith(Java.class).to(JavaService.class);
  13. binder.bind(Service.class).annotatedWith(com.edurt.sli.guice.multiple.Guice.class).to(GuiceService.class);
  14. binder.requestStaticInjection(ApplicationStatic.class);
  15. });
  16. ApplicationStatic.guice.print("sss");
  17. ApplicationStatic.java.print("sss");
  18. }
  19. }

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

  1. Guice Service sss
  2. Java Service sss

属性绑定多接口


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

  1. package com.edurt.sli.guice.multiple;
  2. import com.google.inject.Guice;
  3. import com.google.inject.Inject;
  4. public class ApplicationMultipleProperty {
  5. @Inject
  6. public Service java;
  7. @Inject
  8. public Service guice;
  9. public static void main(String[] args) {
  10. ApplicationMultipleProperty application = Guice.createInjector(binder -> {
  11. binder.bind(Service.class).annotatedWith(Java.class).to(JavaService.class);
  12. binder.bind(Service.class).annotatedWith(com.edurt.sli.guice.multiple.Guice.class).to(GuiceService.class);
  13. }).getInstance(ApplicationMultipleProperty.class);
  14. application.guice.print("sss");
  15. application.java.print("sss");
  16. }
  17. }

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

  1. Exception in thread "main" com.google.inject.ConfigurationException: Guice configuration errors:
  2. 1) No implementation for com.edurt.sli.guice.multiple.Service was bound.
  3. Did you mean?
  4. * com.edurt.sli.guice.multiple.Service annotated with interface com.edurt.sli.guice.multiple.Java
  5. * com.edurt.sli.guice.multiple.Service annotated with interface com.edurt.sli.guice.multiple.Guice
  6. while locating com.edurt.sli.guice.multiple.Service
  7. for field at com.edurt.sli.guice.multiple.Application.guice(Application.java:6)
  8. while locating com.edurt.sli.guice.multiple.Application
  9. 2) No implementation for com.edurt.sli.guice.multiple.Service was bound.
  10. Did you mean?
  11. * com.edurt.sli.guice.multiple.Service annotated with interface com.edurt.sli.guice.multiple.Java
  12. * com.edurt.sli.guice.multiple.Service annotated with interface com.edurt.sli.guice.multiple.Guice
  13. while locating com.edurt.sli.guice.multiple.Service
  14. for field at com.edurt.sli.guice.multiple.Application.java(Application.java:6)
  15. while locating com.edurt.sli.guice.multiple.Application
  16. 2 errors
  17. at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1120)
  18. at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1078)
  19. at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1131)
  20. at com.edurt.sli.guice.multiple.Application.main(Application.java:18)

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

  1. package com.edurt.sli.guice.multiple;
  2. import com.google.inject.Guice;
  3. import com.google.inject.Inject;
  4. import com.google.inject.name.Named;
  5. import com.google.inject.name.Names;
  6. public class ApplicationMultipleProperty {
  7. @Inject
  8. @Named("Java")
  9. public Service java;
  10. @Inject
  11. @Named("Guice")
  12. public Service guice;
  13. public static void main(String[] args) {
  14. ApplicationMultipleProperty application = Guice.createInjector(binder -> {
  15. binder.bind(Service.class).annotatedWith(Names.named("Java")).to(JavaService.class);
  16. binder.bind(Service.class).annotatedWith(Names.named("Guice")).to(GuiceService.class);
  17. }).getInstance(ApplicationMultipleProperty.class);
  18. application.guice.print("sss");
  19. application.java.print("sss");
  20. }
  21. }

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

  1. Guice Service sss
  2. Java Service sss

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

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

打包文件部署


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

运行打包后的文件即可

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

源码地址