• 依赖注入框架之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地址

  • 相关阅读:
    javascript转换时间戳
    解决 Out of range value adjusted for column 'ID' at row 1
    解决 ERROR in native method: JDWP No transports initialized, jvmtiError=AGENT_ERROR_TRANSPORT_INIT(197)
    解决 nfs挂载错误wrong fs type, bad option, bad superblock
    修改浏览器Cookie
    elasticsearch备忘
    itextpdf 备忘
    重命名和移动
    win10 教育版本变专业版本
    解决com.intellij.openapi.project.IndexNotReadyException: Please change caller according to com.intellij.
  • 原文地址:https://www.cnblogs.com/strongmore/p/16121649.html
Copyright © 2020-2023  润新知