【问题标题】:HK2 equivalent Assisted Injection with FactoryModuleBuilder使用 FactoryModuleBuilder 的 HK2 等效辅助注入
【发布时间】:2015-01-22 10:08:49
【问题描述】:

感谢迁移到球衣 2,我需要从 guice 迁移到 HK2。对于我的一些依赖项,我有一个辅助注入方法,我无法在 HK2 中实现这些依赖项。看起来它应该通过Custom Injection Resolvers 解决,但我真的不知道如何解决。这些例子对我来说不够清楚..

这是它在 Guice 上的外观:

public interface MyFactory {
    public MyClass createMyClass(@Assisted String dynamicParameter);
    public HisClass createHisClass(@Assisted String dynamicParameter);
    ...
}

binder.install(new FactoryModuleBuilder().build(MyFactory.class));

public class MyClass {
   ...
   @Inject
   public MyClass(@Assisted String dynamicParameter, SomeService someOtherServiceInjectedAutomatically){
      ...
   }
}

如何在 HK2 上实现这个?

【问题讨论】:

    标签: java dependency-injection jersey-2.0 hk2


    【解决方案1】:

    发布问题后,我想这样做:

    public class MyFactoryImpl implements MyFactory{
    
       private final SomeService someService;
    
       @Inject
       public MyFactoryImpl(SomeService someService){
          this.someService = someService;
       }
    
       public MyClass createMyClass(String dynamicParameter){
          return new MyClass(dynamicParameter, someService);
       }
    
       ...
    }
    

    【讨论】:

      【解决方案2】:

      有一个Guice-Bridge :-D

      <dependency>
          <groupId>org.glassfish.hk2</groupId>
          <artifactId>guice-bridge</artifactId>
          <version>${hk2.version}</version>
      </dependency>
      

      这是一个使用 Guice 3.0 和 HK2 2.3.0(与 Jersey 2.13 捆绑在一起)的示例。这只是一个独立的,但它应该在 Jersey 环境中同样工作。

      Guice 类

      public class GuiceGreeter {
          public String getGreeting(String name) {
              return "Hello, " + name;
          }
      }
      
      import com.google.inject.assistedinject.Assisted;
      import javax.inject.Inject;
      
      public class Message {
          private final String message;  
          @Inject
          public Message(GuiceGreeter greeter, @Assisted String name) {
              message = greeter.getGreeting(name);
          }
          public String getMessage() {
              return message;
          }
      }
      
      public interface GuiceMessageFactory {
          public Message getMessage(String name);
      }
      
      import com.google.inject.AbstractModule;
      import com.google.inject.assistedinject.FactoryModuleBuilder;
      
      public class GuiceMessageModule extends AbstractModule {
          @Override
          protected void configure() {
              install(new FactoryModuleBuilder().build(GuiceMessageFactory.class));
              bind(GuiceGreeter.class);
          }   
      }
      

      HK2服务,注入Guice工厂

      import javax.inject.Inject;
      
      public class HK2Service {
          private final GuiceMessageFactory messageFactory;
      
          @Inject
          public HK2Service(GuiceMessageFactory messageFactory) {
              this.messageFactory = messageFactory;
          }
      
          public void printMessage(String name) {
              System.out.println(messageFactory.getMessage(name).getMessage());
          }
      }
      

      主要

      import com.google.inject.Guice;
      import com.google.inject.Injector;
      import org.glassfish.hk2.api.ServiceLocator;
      import org.glassfish.hk2.api.ServiceLocatorFactory;
      import org.glassfish.hk2.utilities.ServiceLocatorUtilities;
      import org.jvnet.hk2.guice.bridge.api.GuiceBridge;
      import org.jvnet.hk2.guice.bridge.api.GuiceIntoHK2Bridge;
      
      public class Main {
          public static void main(String[] args) {
              // Create service locator. In Jersey context, you should be able to
              // inject the `ServiceLocator` into the `Application/ResourceConfig` 
              // subclass constructor, or as a field
              ServiceLocatorFactory factory = ServiceLocatorFactory.getInstance();
              ServiceLocator locator = factory.create("SimpleServiceLocator");
      
              // bridge the two frameworks to allow Guice injected services
              GuiceBridge.getGuiceBridge().initializeGuiceBridge(locator);
              Injector injector = Guice.createInjector(new GuiceMessageModule());
              GuiceIntoHK2Bridge guiceBridge = locator.getService(GuiceIntoHK2Bridge.class);
              guiceBridge.bridgeGuiceInjector(injector);
      
              // Add my HK2 Service
              ServiceLocatorUtilities.addClasses(locator, HK2Service.class);
      
              // Look up HK2 service. If this lookup works, `@Inject` in Jersey should.
              HK2Service service = locator.getService(HK2Service.class);
              service.printMessage("peeskillet");
          }
      }
      

      这会打印出"Hello, peeskillet"。请参阅下面的评论 main 在 Jersey 应用程序中获取 ServiceLocator 的方法。如果您对ServiceLocator 不熟悉,您使用AbstractBinder 添加的所有绑定也将被放入服务定位器上下文中,因此您不必像上面使用@ 那样显式添加类987654331@。

      【讨论】:

      • 虽然在我决定让 Guice 作为我的 DI 的情况下,这对我来说是一个有用的答案,但这并不是对所提问题的回答。所以我不能将其标记为答案,但我会给 +1 :);谢谢..
      • 我会在有时间使用 InjectionResolver 示例时进行更新。
      • 我收回了。在花了一些时间思考如何复制 Guice 功能后,我意识到以通用方式复制并非易事。 Guice 中有超过 1000 行代码来为FactoryModuleBuilder API 创建这个功能。它涉及大量的反思。为单个用例创建功能并没有那么复杂,但它仍然涉及到比你在答案中所拥有的更多的东西。在不需要时使用框架 API 使事情变得过于复杂是没有意义的。
      • 我会说如果你经常使用这个功能,也许考虑使用网桥只是为了利用这个功能。您仍然可以将 HK2 用于其他所有内容。如果您不经常使用它,那么您的解决方案可能是针对单个用例最容易实施的解决方案。
      • 是的,再想一想,实现我的工厂类并没有那么大的麻烦。我错误地解决了这个问题,并专注于找到一种方法来复制该功能,同时尝试手动解决它就好了。那我会把我的标记为答案。非常感谢@peeskillet。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多