美文网首页工作生活
Google Guice 分析

Google Guice 分析

作者: 走在成长的道路上 | 来源:发表于2019-07-02 20:28 被阅读0次

    最近工作中使用到了 Presto 作为分布式即席查询引擎,其中插件相关的管理基本使用 Guice 注入框架进行插件生命周期管理,因此在此对 Guice 进行简单分析。

    常见类说明

    类名 说明
    Guice 框架注册入口
    Injector 注入器声明主类
    Binder 接口类与实现之间的绑定器
    Module 管理及建立Binder关系的类
    Provider 注入服务提供者,与 Module 中配置效果一致
    Key Provider 键名,类似 spring 中 Bean 的名称,与 Provider 一对一关系
    Scope Provider 的作用范围

    因此,可以简单进行如下理解:

    • Guice 依据 Module 中的配置,将接口与实现类建立绑定关系,在 Injector 中形成接口与实现之间的 Mapping 关系
    • 在 Injector 中的 Mapping 中 使用 Binding 来维护绑定关系,其中用 Key 来维护接口(在 Key 中通常也会含有一个 Annotation 属性,用来标记当前接口所指定的那个实现类名称),用 Provider 来维护实现
    • 通过 injector.getInstance(XXX.class) 的方式创建对应接口的实例, 亦可使用 @inject 标注来完成

    实例说明

    1. 构建 Module 对象
    • 普通方式
    import com.google.inject.AbstractModule;
    
    public class BasicModule extends AbstractModule {
    
        @Override
        protected void configure() {
            // 将 ILogger 与 LoggerImpl 进行绑定
            bind(Key.get(ILogger.class, Names.named("ilogger1"))).to(LoggerImpl.class);
            bind(Key.get(ILogger.class, Names.named("ilogger2"))).to(Logger2Impl.class);
    
            // 或者通过 普通接口,标记注解内容,临时创建 Provider 的方式进行
            bind(ILogger.class).annotatedWith(Names.named("ilogger1")).toProvider(new Provider<ILogger>() {
                @Override
                public ILogger get() {
                    return new LoggerImpl();
                }
            });
    
            // 将 Logger 实例绑定为 new Logger(true) 
            bind(Logger.class).toInstance(new Logger(true));
        }
    }
    
    • 注解方式
    public class BasicModule extends AbstractModule {
        @Override
        protected void configure() {
            bind(Logger.class).toInstance(new Logger(true));
        }
    
        @Provides
        @Singleton
        @Named("ilogger1")
        public ILogger getILogger1() {
            return new LoggerImpl();
        }
    
        @Provides
        @Singleton
        @Named("ilogger2")
        public ILogger getILogger2() {
            return new Logger2Impl();
        }
    }
    
    public class StringModule extends AbstractModule {
    
        @Override
        protected void configure() {
            // 将 String 实例绑定为 "jdbc:phoenix:localhost:2181/hbase"
            bind(String.class).annotatedWith(Names.named("url")).toInstance("jdbc:phoenix:localhost:2181/hbase");
        }
    
    }
    

    多实现接口定义及使用过程中均需要通过 @Named 注解进行名称绑定,否则会出现 A binding to XXX was already configured at YYY

    1. 定义接口及其实现
    public interface ILogger {
        boolean log(String message);
    }
    
    public class LoggerImpl implements ILogger {
        public boolean log(String message) {
            System.out.println("Logger Message: " + message);
            return true;
        }
    }
    
    public class Logger2Impl implements ILogger {
        public boolean log(String message) {
            System.out.println("Logger2 Message: " + message);
            return true;
        }
    }
    
    1. 测试运行
    import com.google.inject.*;
    import com.google.inject.name.Named;
    
    import java.util.Map;
    
    public class Logger {
        private boolean hasEnabled;
    
        @Inject
        @Named("ilogger1")
        private ILogger iLogger1;
    
        @Inject
        @Named("ilogger2")
        private ILogger iLogger2;
    
        public Logger(boolean enabled) {
            if (enabled) {
                hasEnabled = enabled;
                System.out.println("Logger has enabled");
            }
        }
    
        public boolean log(String message) {
            if (hasEnabled) {
                iLogger1.log(message);
            }
            return true;
        }
    
    
        public boolean log2(String message) {
            if (hasEnabled) {
                iLogger2.log(message);
            }
            return true;
        }
    
        public static void main(String[] args) {
            // 同时配置两个模块: BasicModule 和 StringModule
            Injector injector = Guice.createInjector(new BasicModule(), new StringModule());
            Logger logger = injector.getInstance(Logger.class);
            String url = injector.getInstance(Key.get(String.class, Names.named("url")));
            logger.log("hello world  111");
            logger.log2("hello world  222");
            System.out.println("******" + url + "******");
            System.out.println();
    
            Map<Key<?>, Binding<?>> bindings = injector.getAllBindings();
            for (Map.Entry<Key<?>, Binding<?>> bingingEntry : bindings.entrySet()) {
                Binding binging = bingingEntry.getValue();
                Key key = binging.getKey();
                Provider provider = binging.getProvider();
                System.out.println("Key: " + key.toString());
                System.out.println("Provider: " + provider.get().getClass());
                System.out.println("************");
            }
        }
    }
    

    其输出内容如下:

    Logger has enabled
    Logger Message: hello world  111
    Logger2 Message: hello world  222
    ******jdbc:phoenix:localhost:2181/hbase******
    
    Key: Key[type=com.google.inject.Stage, annotation=[none]]
    Provider: class com.google.inject.Stage
    ************
    Key: Key[type=com.google.inject.Injector, annotation=[none]]
    Provider: class com.google.inject.internal.InjectorImpl
    ************
    Key: Key[type=java.util.logging.Logger, annotation=[none]]
    Provider: class java.util.logging.Logger
    ************
    Key: Key[type=com.devhub.guice.Logger, annotation=[none]]
    Provider: class com.devhub.guice.Logger
    ************
    Key: Key[type=com.devhub.guice.ILogger, annotation=@com.google.inject.name.Named(value=ilogger1)]
    Provider: class com.devhub.guice.LoggerImpl
    ************
    Key: Key[type=com.devhub.guice.ILogger, annotation=@com.google.inject.name.Named(value=ilogger2)]
    Provider: class com.devhub.guice.Logger2Impl
    ************
    Key: Key[type=com.devhub.guice.Logger2Impl, annotation=[none]]
    Provider: class com.devhub.guice.Logger2Impl
    ************
    Key: Key[type=com.devhub.guice.LoggerImpl, annotation=[none]]
    Provider: class com.devhub.guice.LoggerImpl
    ************
    
    Process finished with exit code 0
    

    多实现接口使用应与其定义一致,使用 @Named 注解进行标注名称

    由上述例子可看出,Named 中定义的名称会被存放到 Key 中,从而区别不同的实现

    如上述所示,可同时注入多个 Module ,每个 Module 配置不同的内容,从而将接口实现进行多类型,方便模块公用

    Gradle 依赖库

    compile group: 'com.google.inject', name: 'guice', version: '4.2.2'
    

    参考

    相关文章

      网友评论

        本文标题:Google Guice 分析

        本文链接:https://www.haomeiwen.com/subject/dcazcctx.html