天道酬勤,学无止境

Guice - 绑定由辅助注入工厂创建的实例(Guice - Binding an instance created by assisted injection factory)

问题

假设有一个类 A 的构造函数看起来像这样:

public A(@Assited long id, @Assisten String name, ServiceA serviceA, ServiceB serviceB)

还有 AFactory:

public interface AFactory{

    A create(long id, String name);
}

所以要创建一个 AI 实例显然需要做这样的事情:

injector = Guice.createInjector(new MyModule());
AFactory af = injector.getInstance(AFactory .class);
A a = AFactory.create(100, "mike");

但是,假设我有其他类:B 类、C 类和 D 类,它们具有类型 A 的成员,例如(具有字段注入但也可以是 ctor):

    public class B{
       @Inject
       A a;
    }

我希望将 A 的相同实例注入这些类。 但仍然可以选择将 A 的另一个实例注入其他类(假设是 E 类和 F 类)。

这样做的正确方法是什么? 我只是想不出一个干净的方法来做到这一点。

回答1

您可以构建您的模块以使用 Providers(我在下面使用 @Provides 方法,但如果您愿意,您可以使用完整的 Provider 类或实例),并将一致的 A 标记为 @Singleton。 如果你想要A的两个绑定(一致和不一致),至少其中一个应该打上绑定注解; 为方便起见,我在这里使用@Named ,但您可以使用文档中列出的任何绑定注释。

public class AModule extends AbstractModule {
  @Override public void configure() {
    // Install your AFactory module. Here, injections for AFactory should succeed.
    install(new FactoryModuleBuilder().build(AFactory.class));
  }

  /**
   * Provides a singleton @Named("consistent") A.
   * Inject @Named("consistent") A into B, C, and D; Guice will cache the instance.
   */
  @Provides @Singleton @Named("consistent")
      A provideConsistentA(AFactory factory) {
    return factory.create(100, "mike");
  }

  /**
   * Provides an unscoped A.
   * Inject A without an annotation into E and F; each instance will be separate.
   */
  @Provides @Singleton A provideUnscopedA(AFactory factory) {
    return factory.create(200, "jeff");
  }
}

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • Guice辅助注入使依赖层次更深(Guice assisted injection deeper down the dependency hierarchy)
    问题 我想进行一系列处理,并通过Guice将它们连接在一起。 让我们假设以下路径: 由class AImpl实现的interface A需要一些输入由class BImpl实现的interface B需要A 由class CImpl实现的interface C需要B 由class DImpl实现的interface D需要C A的依赖关系只能在运行时解决,而不能在配置时解决。 通常的方法是在这种情况下使用“辅助注入”来创建一个工厂,该工厂将缺少的实例作为参数,如下所示: public interface AFactory { public A createA(String input); } 但是我真正想要的是这样的: public interface DFactory { public D createD(String inputForA); } 我不想在整个层次结构中手动传递特定于AImpl依赖项。 Guice是否有可能实现这一目标? 如果不是,那么在保持注射益处的同时优雅地解决该问题的最佳方法是什么? 回答1 作弊方式:将input在静态变量或单例ThreadLocal 。 在管道启动之前进行设置,在管道结束之后将其清除。 通过DI绑定其他所有内容。 @PipelineInput String inputString方式:在A ,引用@PipelineInput String
  • Guice可以基于参数自动创建不同类的实例吗?(Can Guice automatically create instances of different classes based on a parameter?)
    问题 标准对象工厂可能如下所示: interface I { ... } class A implements I { ... } class B implements I { ... } class IFactory { I getI(int i) { switch (i) { case 1: return new A(); default: return new B(); } } } 是否可以设置绑定以便为我完成切换,即我要做的就是调用getInstance或inject? 我当时在看辅助注射,但这似乎是另外一个话题:https://code.google.com/p/google-guice/wiki/AssistedInject 回答1 听起来您正在寻找MapBinder,这是Multibindings功能的一部分。 请注意,您仍然需要放入某种IFactory或其他工厂接口,因为getInstance不会像getI那样接受参数,并且仍然需要在某个地方建立从整数到类实现的映射。 MapBinder样式 class IModule extends AbstractModule { @Override public void configure() { MapBinder<Integer, I> myBinder = MapBinder.newMapBinder(binder()
  • 用 Guice 替换抽象工厂?(Replacing abstract factory with Guice?)
    问题 我是 Guice 的新手,我想知道我能走多远。 我有一个UserInfo接口,其中包含多个实现类GoogleUserInfo 、 FacebookUserInfo 、 TwitterUserInfo等。这些类是使用工厂创建的 public class UserInfoFactory { public UserInfo createFromJsonString(String jsonspec) { . . . } } 创建由 JSON 字符串jsonspec控制,该字符串控制返回UserInfo哪些实现类。 具体来说,有一个 JSON 字符串元素domain来控制创建。 创建实际上是使用 GSON 对jsonspec进行反序列化的功能。 我想知道是否有一种用 Guice 依赖注入替换这个创建的好方法? 回答1 您可以将 Guice 集成到工厂中,但在这种情况下,您的代码可能会更好。 这实际上是那些不能轻易替换的工厂之一,因为它必须包含解析jsonSpec并根据它更改它返回的具体类型的逻辑。 假设稍微简化的工厂版本如下所示: public class UserInfoFactory { public UserInfo createFromJsonString(String jsonspec) { if(getUserType(jsonSpec) == TWITTER) {
  • 如何在需要注入实例的 Guice 中进行动态绑定?(How do you make dynamic bindings in Guice that require an injected Instance?)
    问题 我想创建一个将实例动态绑定到命名注释的模块。 用例是我想自动将配置中的值与属性文件中的键作为@Named 值进行绑定。 但是,配置绑定在不同的模块中,因此我需要注入配置。 我看过的解决方案是: 在 configure() 方法中绑定。 此方法未注入,我无法获得基本配置。 使用提供者/@Provides。 提供者只绑定一个实例。 使用 MultiBinder。 我的用例与此扩展提供的用例略有不同。 多重绑定允许您分别绑定多个实例,然后将它们作为更复杂的包含类型的 Collection 注入。 我想分别绑定每个实例,并通过唯一可识别的方式让它们在注入后使用。 使用 childInjector。 不幸的是,如果不对现有代码进行一些广泛的修改,这是不可能的。 这个答案很好地描述了如何以这种方式解决这个问题。 以某种方式注入粘合剂。 (我开始变得有点 hackier)Guice 允许注入 Injector 以备后用,我尝试通过 @Provides 方法将 Binder 注入模块,然后直接使用绑定器在方法内进行多个绑定。 Guice 不会注入粘合剂。 回答1 请记住,在任何注入发生之前,所有configure方法都配置了Injector中的所有绑定。 说了这么多: 将@Named属性绑定到单个Properties实例的内容非常有用,有一个 Names.bindProperties(
  • Google Guice之牛刀小试
    Google Guice由google推出的一开源软件,是超轻量级的,下一代的,为Java 5及后续版本设计的依赖注入容器,其功能类似于如日中天的Spring。 下面我们就来了解一下Guice,在此之前,先看一个官方例子:在应用程序中,要把所有的东西装配起来是一件很乏味的事件,这要涉及到连接数据,服务,表现层类等方面,这是一个比萨饼订购网站的计费代码例子用于这些方面的对比。 public interface BillingService { /** * Attempts to charge the order to the credit card. Both successful and * failed transactions will be recorded. * * @return a receipt of the transaction. If the charge was successful, the * receipt will be successful. Otherwise, the receipt will contain a * decline note describing why the charge failed. */ Receipt chargeOrder(PizzaOrder order, CreditCard creditCard); }
  • Google Guice之绑定方式
    在Guice中,注入器的工作是装配对象图,当请求某一类型实例时,注入器根据对象图来判断如何创建实例、解析依赖。要确定如何解析依赖就需要通过配置注入器的绑定方式。 要创建绑定(Binding)对象,可以继承自AbstractModule类,然后覆盖其configure方法,在方法调用bind()方法来指来定每一次绑定,这些方法带有类型检查,如果你使用了错误的类型编译器就会报告编译错误。如果你已经写好了Module类,则创建一个Module类对象作为参数传递给Guice.createInjector()方法用于创建一个注入器。 通过Module对象可以创建链接绑定(linked bindings)、实例绑定(instance bindings)、@Provides methods、提供者绑定(provider bindings)、构建方法绑定(constructor bindings)与无目标绑定(untargetted bindings)。这些绑定方式统称为内置绑定,相对应的还有种及时绑定,如果在解析一个依赖时如果在内置绑定中无法找到,那么Guice将会创建一个及时绑定。 一、链接绑定(LinkdedBindings) 链接绑定即映射一类型到它的实现类,例如映射TransactionLog接口到实现类DatabaseTransactionLog: public class
  • 如何将辅助注入类绑定到接口?(How to bind Assisted Injected class to interface?)
    问题 这是我遇到的问题: Class SimpleCommand implements Executable{ private final ConfigManager config; private String name; @Inject public SimpleCommand(ConfigManager config, @Assisted String name){ this.config = config; this.name = name; } } Class MyModule extends AbstractModule{ @Override protected void configure() { bind(CommandFactory.class).toProvider(FactoryProvider.newFactory(CommandFactory.class, SimpleCommand.class)); bind(Executable.class).to(SimpleCommand.class); } } 当我尝试使用以下方法获取 SimpleCommand 实例时: Guice.createInjector(new MyModule()).getInstance(CommandFactory.class).create("sample command")
  • 匕首2:将用户输入的参数注入对象(Dagger 2: Injecting user inputted parameter into object)
    问题 说我有一个类的Util这需要一个对象-类验证器的一个实例。 由于我想避免在Util中实例化Validator类,因此我通过构造函数将其传递给它: public class Util { @Inject public Util(Validator validator) { } } 我有一个提供Validator实例的模块: @Provides @Singleton Validator provideValidator() { return Validator.getInstance(); } 以及一个Util类的实例: @Provides Util provideUtil(Validator validator) { return new Util(validator); } 我连接了一个组件,该组件可以为我提供一个Util实例: Util getUtil() 所以在我的活动中,我可以这样称呼它: Util myUtil = getComponent.getUtil(); 所有这些都可以正常工作-myUtil在实例化时具有Validator类的适当实例。 现在,我想传递一个名为address的String变量(用户通过UI输入)。 我想更改构造函数,以便同时传入Validator的实例和用户输入的String: @Inject public Util(Validator
  • Google Guice之注入方式
    在Guice中,注入方式有如下几种: 一、构造器注入(Constructor Injection) 使用构造器注入只要在构造方法上添加一个@Inject注解,该构造方法接收一些依赖参数,大多数的构造方法将这些参数赋值给final字段。 public class RealBillingService implements BillingService { private final CreditCardProcessor processorProvider; private final TransactionLog transactionLogProvider; @Inject public RealBillingService(CreditCardProcessor processorProvider, TransactionLog transactionLogProvider) { this.processorProvider = processorProvider; this.transactionLogProvider = transactionLogProvider; } } 如果有一个类没有添加了@Inject注解的构造方法,那么Guice使用一个public的、没有参数的构造方法,如果该构造方法存在的话。 构造器依赖易于单元测试
  • 寻找Dagger辅助注射的例子(Looking for an example for Dagger assisted injection)
    问题 来自dagger-discuss @: 我有一个类,它从对象图中获取一些依赖关系,而在运行时从调用者那里获取其他依赖关系。 public class ImageDownloader { // Get these dependencies from the injector. private final HttpClient httpClient; private final ExecutorService executorService; // Get these from the caller. private final URL imageUrl; private final ImageCallback callback; ... } 我想出了一个解决方案,在其中定义了一个Factory, public class ImageDownloader { ... public static class Factory { private final HttpClient httpClient; private final ExecutorService executorService; @Inject public Factory(HttpClient httpClient, ExecutorService executorService) { this.httpclient
  • 在Guice注入一家通用工厂(Injecting a generic factory in Guice)
    问题 以下代码是工厂的示例,该工厂在给定Foo<T>产生Bar<T> Foo<T> 。 工厂不在乎T是什么:对于任何T类型,它都可以从Foo<T>生成Bar<T> Foo<T> 。 import com.google.inject.*; import com.google.inject.assistedinject.*; class Foo<T> { public void flip(T x) { System.out.println("flip: " + x); } } interface Bar<T> { void flipflop(T x); } class BarImpl<T> implements Bar<T> { Foo<T> foo; @Inject BarImpl(Foo<T> foo) { this.foo = foo; } public void flipflop(T x) { foo.flip(x); System.out.println("flop: " + x); } } interface BarFactory { <T> Bar<T> create(Foo<T> f); } class Module extends AbstractModule { public void configure() { bind(BarFactory.class)
  • 如何通过 Roboguice 中的构造函数注入参数? [安卓](How can I inject parameter through constructor in Roboguice? [android])
    问题 这个问题可能与 Guice 的这个 Pass 参数给构造函数完全相同 不同之处在于我将 roboguice 用于 android,而不仅仅是 Guice,所以那里的答案对我不起作用。 问题是 - 如何将初始化参数传递给创建的对象? 即我已经注入了接口,该接口应该用一些 roboguice 不知道的参数进行初始化。 我在提供的链接中看到的内容,我应该创建工厂接口并像这样注册 void configure(Binder binder) { binder.install(new FactoryModuleBuilder() .implement(FooInterface.class, Foo.class) .build(FooFactory.class)); } 但我找不到FactoryModuleBuilder类。 我使用 Intellij IDEA,它可以向我显示我可以在当前位置访问的每个类,并且我可以 100% 确定没有以“工厂”字样开头的类。 如何使用 roboguice 创建我的工厂? 更新 我忘了下载 guice 辅助注射。 但是我仍然不知道我应该在哪里注册这家工厂。 更新 2 为什么我需要那个? 因为应该存在某些抽象具有 Roboguice 无法解决的依赖关系的情况。 这种依赖可以是任何类型,甚至是简单的字符串或数字。 在我的例子中,我在 UI 上有
  • Guice,JDBC和管理数据库连接(Guice, JDBC and managing database connections)
    问题 我希望在学习Guice的同时创建一个示例项目,该项目使用JDBC读取/写入SQL数据库。 但是,在使用Spring多年之后,让它抽象化了连接处理和事务,我一直在努力从概念上进行操作。 我想要一个可以启动和停止事务并调用大量存储库的服务,这些存储库可以重用相同的连接并参与相同的事务。 我的问题是: 我在哪里创建数据源? 如何授予存储库访问连接的权限? (ThreadLocal?) 管理事务的最佳方法(为注释创建拦截器吗?) 下面的代码显示了我如何在Spring中执行此操作。 注入到每个存储库中的JdbcOperations可以访问与活动事务关联的连接。 除了显示如何为事务创建拦截器的教程以外,我还没有找到很多涵盖此内容的教程。 我对继续使用Spring感到很满意,因为它在我的项目中运行良好,但是我想知道如何在纯Guice和JBBC中做到这一点(不使用JPA / Hibernate / Warp / Reusing Spring) @Service public class MyService implements MyInterface { @Autowired private RepositoryA repositoryA; @Autowired private RepositoryB repositoryB; @Autowired private RepositoryC
  • 使用 Dagger 对构造函数进行依赖注入(Using Dagger for dependency injection on constructors)
    问题 所以,我目前正在重新设计我的一个 Android 应用程序以使用 Dagger。 我的应用程序又大又复杂,最近我遇到了以下场景: 对象 A 需要一个特殊的 DebugLogger 实例,它是注入的完美候选者。 而不是传递记录器,我可以通过 A 的构造函数注入它。 这看起来像这样: class A { private DebugLogger logger; @Inject public A(DebugLogger logger) { this.logger = logger; } // Additional methods of A follow, etc. } 到目前为止,这是有道理的。 但是,A 需要由另一个类 B 来构造。 A 的多个实例必须构造,所以按照 Dagger 的做事方式,我简单地将一个Provider<A>注入到 B 中: class B { private Provider<A> aFactory; @Inject public B(Provider<A> aFactory) { this.aFactory = aFactory; } } 好的,到目前为止还好。 但是等等,突然 A 需要额外的输入,例如一个称为“金额”的整数,这对其构造至关重要。 现在,我的 A 构造函数需要如下所示: @Inject public A(DebugLogger logger
  • 我如何让 google guice 注入自定义记录器,例如 commons-logging 或 log4j 记录器(How do I get google guice to inject a custom logger, say a commons-logging or log4j logger)
    问题 Google guice 有一个内置的记录器绑定。 但是如果我想使用 commons-logging 或 log4j 记录器怎么办? 我可以得到 guice 注入由创建的日志吗 LogFactory.getLog(CLASS.class) 但具有与内置绑定相同的行为: 绑定会自动将记录器的名称设置为将记录器注入到其中的类的名称。 它甚至有意义吗? 还是喊我干脆用内置的java Logger? 或者只使用 commons-logging 而不注入? 回答1 Guice wiki 上的 CustomInjections 页面准确地描述了如何注入由它被注入的类命名的记录器。 回答2 这是你的选择。 我已经使用 wiki 上详述的方法成功地将logback与 Guice 一起使用。 看看 sli4j 项目。 它可能有用。 回答3 Guice 对于注入接口的不同实现非常有用。 情况并非如此,因为不同的日志实现都有不同的 API。 如果您希望稍后在针对接口进行开发时能够交换实际的日志记录实现,请使用公共日志记录或 slf4j。 回答4 尽管您无法覆盖提供的java.util.logging.Logger记录器,但您可以像绑定任何其他类一样绑定一个新的记录器: bind(Log.class).to(LogFactory.getLog(YourClass)); // or
  • Guice:如何绑定由已绑定对象动态获取的类?(Guice : How to bind classes that are dynamically obtained by an already binded object?)
    问题 我正在使用Guice开发一个小型Web框架。 我有一个Router对象,该对象一旦初始化,便公开了getControllerClasses()方法。 我必须遍历所有那些动态返回的类,以使用Guice绑定()它们。 我绑定路由器: bind(IRouter.class).to(Router.class); 但是,然后,如何在模块中获取绑定的Router实例,以便也可以绑定其getControllerClasses()方法返回的类? 我能够在一个模块中获取Router实例的唯一方法是,将该实例绑定到第一个模块中,然后在setter上使用@Inject将其注入到第二个模块中: 模块1 bind(IRouter.class).to(Router.class); Module2 module2 = Module2(); requestInjection(module2); install(module2); 模块2 @Inject public void setRouter(IRouter router) { Set<Class<?>> controllerClasses = router.getControllerClasses(); for(Class<?> controllerClass : controllerClasses) { bind(controllerClass);
  • Dropwizard 和 Guice:注入环境(Dropwizard and Guice: injecting Environment)
    问题 我目前正在构建一个基于 Dropwizard + Guice + Jersey 的应用程序,其中数据库访问暂时由 JDBI 处理。 我想要实现的是拥有典型的企业架构,其中资源访问服务类,访问 DAO 类,DAO 类又访问数据库。 以适当的 DI 方式将所有这些连接起来会很好,尽管我想如果所有其他方法都失败了,我可以在应用程序的 run() 方法中构建我的对象图。 所以,我遇到了之前在这里提到的这个问题:获取 DBIFactory 需要环境和配置,这需要在 Guice 执行注入魔法时可用,而不是在 run() 时可用. 作为一个 Dropwizard 和 Guice 菜鸟,到目前为止我已经设法把我的 DAO 对象放在一起,我需要一个 public class UserDAOProvider implements Provider<UserDAO> { @Inject Environment environment; @Inject Configuration configuration; @Override public UserDAO get() { final DBIFactory factory = new DBIFactory(); final (MyConfiguration) config = (MyConfiguration) configuration; DBI
  • Guice Persist是否提供事务范围的或应用程序管理的EntityManager?(Does Guice Persist provide transaction scoped or application managed EntityManager?)
    问题 我们使用Guice Persist在我们的项目中注入EntityManager。 例如 public class MyDao{ @Inject EntityManager em; public void someMethod(){ //uses em instance } } 但是我们不清楚如何使用EntityManager注入实例。 这是什么类型的EntityManager? (请参见:例如,实体管理器的类型)Guice Persist在后台通过EntityManagerFactory.createEntityManager()实例化它,因此我想说它是由应用程序管理的实体管理器。 但是在官方的Wiki中,他们写到了每次交易的渗透策略,这表明EntityManager是(伪)事务作用域的。 我们应该手动调用close()吗? 还是Guice会照顾好它? 一级缓存的范围是什么? 仅单个事务(例如在事务范围的实体管理器中)还是只要我使用相同的EntityManager注入实例(例如在应用程序管理的实体管理器中)? 回答1 尽管Piotr完美地回答了这个问题,但我还是想对如何使用guice-persist提出一些实用建议。 我遇到了很难调试的问题。 在我的应用程序中,某些线程将显示过时的数据,有时EntityManager实例保留有旧的无效数据库连接。 根本原因是通过我使用
  • 在运行时更改Guice绑定(Changing Guice bindings at runtime)
    问题 我希望能够在运行时更改Guice注入以支持基于用户输入的多次注入。 这是我要实现的目标: public interface IDao { public int someMethod(); } public class DaoEarth implements IDao { @Override public int someMethod(){ ... } } public class DaoMars implements IDao { @Override public int someMethod(){ ... } } public class MyClass { @Inject private IDao myDao; public int myMethod(String domain) { //If Domain == Earth, myDao should be of the type DaoEarth //If Domain == DaoMars, myDao should be of the type DaoMars } } 我当时在考虑编写自己的提供程序,但我不知道如何在运行时使用该提供程序更改绑定。 任何意见都是值得欢迎和赞赏的:)! 更新这是我目前想出的,它不如我想要的漂亮,因此我仍在寻找反馈 public class DomainProvider {
  • Guice的架构分析
    Guice 的架构分成两个不同的阶段:启动和运行。 1.启动阶段 执行流程如下: (1)首先创建自定义模块类实例,并将其传入 Guice.createInjector()。 (2)Guice 创建一个绑定器Binder,并将其传入自定义模块。 (3)自定义模块使用绑定器来定义绑定。 (4)基于自定义模块所定义的绑定,Guice 创建一个注入器Injector,并将其返回给自定义模块。 (5)自定义模块使用注入器来注入对象。 2.运行阶段 可以使用启动阶段创建的注入器来注入对象并内省(introspect)我们的绑定。Guice运行时的模型由一个可管理一定数量绑定的注入器组成。Guice运行模型如图1所示。 图1 Guice运行模型 Key键唯一地确定每一个绑定,它包含了客户代码所依赖的类型及一个可选的标注,可以使用标注来区分指向同一类型的多个绑定。Key的类型和标注对应于注入时的类型和标注。 每个绑定有一个提供器provider,它提供所需类型的实例。我们可以定义一个类,Guice会创建它的实例。也可以给Guice一个需要绑定的类的实例,同时还可以实现我们自己的provider,Guice可以向其中注入依赖关系。 每个绑定还有一个可选的作用域。缺省情况下绑定没有作用域,Guice为每一次注入创建一个新的对象,定制的作用域可以使我们控制 Guice 是否创建新对象。例如