依赖注入框架之Guice简单使用

前言

今天在学习Apollo(配置中心)的客户端源码时,发现其中使用到了guice,它是谷歌推出的一个轻量级(相比Spring)的依赖注入框架,在很多开源项目中都有用到,如elasticsearch,maven等。

添加依赖

复制<dependency>
  <groupId>com.google.inject</groupId>
  <artifactId>guice</artifactId>
  <version>4.0</version>
</dependency>

简单定义Bean和依赖注入

复制import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;

/**
 * 测试Guice的依赖注入
 */
public class Client {

  public static void main(String[] args) {
    Injector injector = Guice.createInjector();
    UserService userService = injector.getInstance(UserService.class);
    userService.queryUser();
  }

  @Singleton
  private static class AddressService {

    public String queryCity() {
      return "百度地图";
    }
  }

  @Singleton
  private static class UserService {

    @Inject
    private AddressService addressService;

    public void queryUser() {
      System.out.println(addressService.queryCity());
    }
  }
}

使用@Singleton注解定义一个Bean(参考Spring中的叫法),表示它是单例的(不加的话每次都会创建一个新的对象),类似Spring中的@Component注解。使用@Inject注解注入一个Bean,类似Spring中的@Autowired注解。创建一个注射器Injector,根据它拿到相应类型的Bean。(这里为了代码看起来更直观,所以定义成了内部类)

一个接口多个实现的依赖注入

复制import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import com.google.inject.name.Names;

/**
 * 测试Guice的依赖注入
 */
public class Client {

  public static void main(String[] args) {
    try {
      Injector injector = Guice.createInjector(new MyModule());
      UserService userService = injector.getInstance(UserService.class);
      userService.queryUser();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  private static interface AddressService {

    String queryCity();

  }

  @Singleton
  private static class BaiduAddressService implements AddressService {

    @Override
    public String queryCity() {
      return "百度地图";
    }
  }

  @Singleton
  private static class GaodeAddressService implements AddressService {

    @Override
    public String queryCity() {
      return "高德地图";
    }
  }

  @Singleton
  private static class UserService {

    @Inject
    @Named("gaodeAddressService")
    private AddressService addressService;

    public void queryUser() {
      System.out.println(addressService.queryCity());
    }
  }

  private static class MyModule extends AbstractModule {

    @Override
    protected void configure() {
//      bind(AddressService.class).to(GaodeAddressService.class);
      bind(AddressService.class).annotatedWith(Names.named("gaodeAddressService"))
          .to(GaodeAddressService.class);
      bind(AddressService.class).annotatedWith(Names.named("baiduAddressService"))
          .to(BaiduAddressService.class);
    }
  }

}

一个AddressService接口有两个实现类BaiduAddressService和GaodeAddressService。定义一个自己的Module,自定义装配规则,有两个方式来定义使用哪个实现类

复制bind(AddressService.class).to(GaodeAddressService.class);

表示在注入AddressService类型时找GaodeAddressService。

复制bind(AddressService.class).annotatedWith(Names.named("gaodeAddressService"))
          .to(GaodeAddressService.class);
bind(AddressService.class).annotatedWith(Names.named("baiduAddressService"))
          .to(BaiduAddressService.class);

使用@Named注解来给每一个绑定关系添加注解条件,注入时也使用@Named("gaodeAddressService")来标识,类似Spring的@Qualifier注解的功能。我们也可以使用自定义注解

复制import com.google.inject.AbstractModule;
import com.google.inject.BindingAnnotation;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 测试Guice的依赖注入
 */
public class Client2 {

  public static void main(String[] args) {
    Injector injector = Guice.createInjector(new MyModule());
    UserService userService = injector.getInstance(UserService.class);
    userService.queryUser();
  }

  private static interface AddressService {

    String queryCity();

  }

  @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
  @Retention(RetentionPolicy.RUNTIME)
  @BindingAnnotation
  @interface Baidu {

  }

  @Singleton
  private static class BaiduAddressService implements AddressService {

    @Override
    public String queryCity() {
      return "百度地图";
    }
  }

  @Target({ElementType.TYPE, ElementType.METHOD})
  @Retention(RetentionPolicy.RUNTIME)
  @BindingAnnotation
  @interface Gaode {

  }

  @Singleton
  private static class GaodeAddressService implements AddressService {

    @Override
    public String queryCity() {
      return "高德地图";
    }
  }

  @Singleton
  private static class UserService {

    @Inject
    @Baidu
    private AddressService addressService;

    public void queryUser() {
      System.out.println(addressService.queryCity());
    }
  }

  private static class MyModule extends AbstractModule {

    @Override
    protected void configure() {
      bind(AddressService.class).annotatedWith(Gaode.class).to(GaodeAddressService.class);
      bind(AddressService.class).annotatedWith(Baidu.class).to(BaiduAddressService.class);
    }
  }

}

使用Provider来注入

复制import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Provider;
import com.google.inject.Singleton;

/**
 * 测试Guice的依赖注入
 */
public class Client {

  public static void main(String[] args) {
    try {
      Injector injector = Guice.createInjector(new MyModule());
      UserService userService = injector.getInstance(UserService.class);
      userService.queryUser();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  private static interface AddressService {

    String queryCity();

  }

  @Singleton
  private static class BaiduAddressService implements AddressService {

    @Override
    public String queryCity() {
      return "百度地图";
    }
  }

  @Singleton
  private static class GaodeAddressService implements AddressService {

    @Override
    public String queryCity() {
      return "高德地图";
    }
  }

  private static class AddressServiceProvider implements Provider<AddressService> {

    @Override
    public AddressService get() {
      return new BaiduAddressService();
    }
  }

  @Singleton
  private static class UserService {

    @Inject
    private AddressService addressService;

    public void queryUser() {
      System.out.println(addressService.queryCity());
    }
  }

  private static class MyModule extends AbstractModule {

    @Override
    protected void configure() {
      bind(AddressService.class).toProvider(AddressServiceProvider.class);
    }
  }

}

将AddressService绑定到指定的Provider,由它来决定具体使用哪个实现类,类似Spring中的FactoryBean或ObjectFactory。

AOP使用

复制import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Singleton;
import com.google.inject.matcher.Matchers;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

/**
 * 测试Guice的AOP
 */
public class Client {

  public static void main(String[] args) {
    try {
      Injector injector = Guice.createInjector(new MyModule());
      UserService userService = injector.getInstance(UserService.class);
      userService.queryUser();
      AddressService addressService = injector.getInstance(AddressService.class);
      addressService.queryAddress();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  @Target({ElementType.TYPE, ElementType.METHOD})
  @Retention(RetentionPolicy.RUNTIME)
  @interface Log {

  }

  @Singleton
  public static class UserService {

    @Log
    public void queryUser() {
      System.out.println("this is lisi");
    }
  }

  @Singleton
  public static class AddressService {

    public void queryAddress() {
      System.out.println("this is 上海");
    }
  }

  private static class MyInterceptor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
      System.out.println("method before");
      Object result = invocation.proceed();
      System.out.println("method after");
      return result;
    }
  }

  private static class MyModule extends AbstractModule {

    @Override
    protected void configure() {
      bindInterceptor(Matchers.any(), Matchers.annotatedWith(Log.class), new MyInterceptor());
    }
  }

}

进行AOP拦截的类必须修饰为public或default(包内可见),底层是使用cglib创建代理来实现的,核心类为ProxyFactory。绑定拦截器需要指定类匹配器(拦截哪些类)和方法匹配器(拦截那些方法),Matchers工具类提供了一些匹配器,我们也可以自己定义。

总结

Guice相比Spring少了很多功能,如自动扫描,但也因此更加的灵活和轻便,更多关于Guice的用法,可以查看官方文档

参考

「Guice」依赖注入框架中的小清新
Guice 快速入门
Google Guice
guice-github地址

posted @   strongmore  阅读(595)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示