java - 如何在 guice 提供程序中获取绑定(bind)目标?

标签 java dependency-injection guice

有没有办法获取提供者(或其他方式)中注入(inject)某些内容的类?这是用于日志记录的——当我的 SqlDatabase 执行某些操作时,我希望它以使用它的类的名称显示在日志中。我能想到的最好的方法是获取堆栈跟踪并向后查看它的使用位置,但我真的宁愿在注入(inject)时执行此操作。

提出问题的另一种方式是:我需要找到注入(inject)站点 - 找到 @Inject 注释的确切类 - 以创建注入(inject)类的实例。

最佳答案

我可以想到两种选择:

  1. 声明绑定(bind)时使用 @Provides 方法
  2. 使用Guice AOP这样您就可以记录实际的方法执行情况

这是两种方法的简单示例:

package stackoverflowscrapbook;

import java.util.logging.Logger;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Test;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Provides;
import com.google.inject.matcher.Matchers;

public class TestLogInjectedClassName {

    interface SqlDatabase {
        void doSomething();
    }

    static class SqlDatabaseImpl implements SqlDatabase {

        public void doSomething() {
            System.out.println("foo");
        }

    }

    static class AlternativeImpl implements SqlDatabase {

        public void doSomething() {
            System.out.println("bar");
        }

    }

    class Module extends AbstractModule {

        @Provides
        SqlDatabase database(SqlDatabaseImpl sqlDatabase) {
            Logger.getLogger(TestLogInjectedClassName.Module.class.getName())
                    .info("Providing " + sqlDatabase.getClass());
            return sqlDatabase;
        }

        @Override
        protected void configure() {
            //TODO: other bindings
        }
    }

    class AlternativeModule extends AbstractModule {

        @Provides
        SqlDatabase database(AlternativeImpl sqlDatabase) {
            Logger.getLogger(TestLogInjectedClassName.Module.class.getName())
                    .info("Providing " + sqlDatabase.getClass());
            return sqlDatabase;
        }

        @Override
        protected void configure() {
            //TODO: other bindings
        }
    }

    /**
     * Just log
     */
    class LoggingInterceptor implements MethodInterceptor {

        public Object invoke(MethodInvocation methodInvocation) throws Throwable {
            Logger.getLogger(getClass().getName()).info(methodInvocation.getStaticPart().toString());
            return methodInvocation.proceed();
        }

    }

    /**
     * Binds an interceptor on any method of any class implementing SqlDatabase
     */
    class AopModule extends AbstractModule {

        @Override
        protected void configure() {
            bindInterceptor(Matchers.subclassesOf(SqlDatabase.class), Matchers.any(), new LoggingInterceptor());

        }
    }

    @Test
    public void test() {
        Injector injector = Guice.createInjector(new Module());
        injector.getInstance(SqlDatabase.class);

        Injector anotheInjector = Guice.createInjector(new AlternativeModule());
        anotheInjector.getInstance(SqlDatabase.class);

    }

    @Test
    public void testAop() {
        Injector aopInjector = Guice.createInjector(new AopModule(), new Module());
        aopInjector.getInstance(SqlDatabase.class).doSomething();

        Injector alterntiveAopInjector = Guice.createInjector(new AopModule(), new AlternativeModule());
        alterntiveAopInjector.getInstance(SqlDatabase.class).doSomething();
    }

}

当我运行 test() 时,这是我的控制台

Dec 10, 2017 9:12:15 AM stackoverflowscrapbook.TestLogInjectedClassName$Module database
INFO: Providing class stackoverflowscrapbook.TestLogInjectedClassName$SqlDatabaseImpl
Dec 10, 2017 9:12:15 AM stackoverflowscrapbook.TestLogInjectedClassName$AlternativeModule database
INFO: Providing class stackoverflowscrapbook.TestLogInjectedClassName$AlternativeImpl

当我运行 testAop() 时,这是我的控制台。请注意,在这种情况下,我们会记录注入(inject)和方法的执行。您可以通过删除 @Provides 方法中的日志来选择仅记录执行情况。另请注意,只有当 Guice 创建 SqlDatabase 实例并且其实现中的方法不是最终时,这才有可能。 (我没有格式化下面的日志代码,因为预览中的行被截断了)

2017 年 12 月 10 日上午 9:14:01 stackoverflowscrapbook.TestLogInjectedClassName$Module 数据库 信息:提供类 stackoverflowscrapbook.TestLogInjectedClassName$SqlDatabaseImpl$$EnhancerByGuice$$d7a0782d 2017 年 12 月 10 日上午 9:14:01 stackoverflowscrapbook.TestLogInjectedClassName$LoggingInterceptor 调用 信息:公共(public)无效 stackoverflowscrapbook.TestLogInjectedClassName$SqlDatabaseImpl.doSomething() 富 2017 年 12 月 10 日上午 9:14:01 stackoverflowscrapbook.TestLogInjectedClassName$AlternativeModule 数据库 信息:提供类 stackoverflowscrapbook.TestLogInjectedClassName$AlternativeImpl$$EnhancerByGuice$$3ef8fbf1 2017 年 12 月 10 日上午 9:14:01 stackoverflowscrapbook.TestLogInjectedClassName$LoggingInterceptor 调用 信息:公共(public)无效 stackoverflowscrapbook.TestLogInjectedClassName$AlternativeImpl.doSomething() 酒吧

关于java - 如何在 guice 提供程序中获取绑定(bind)目标?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47683465/

相关文章:

scala - 播放框架 2.5.x : Inject Environment in a Module

java - 如何使用 ServletScopes.scopeRequest() 和 ServletScopes.continueRequest()?

java - Spring Boot @Autowired 在运行时创建实例

java - 如何在 Spring 中使用 @ComponentScan 懒惰地加载所有 bean?

java - 是否可以将特定类型的不可变集绑定(bind)到 Guice 中的实例?

java - 无法从 Java 应用程序打开 orientdb 数据库

Java EE 7 - 注入(inject) Runnable/Callable 对象

javascript - Spring 带有 Thymeleaf 和 DataTables 插件

java - Java 开源拼写检查库

java - 如何使用 SSHJ 通过 SCP 流式传输文件?