当前位置: 首页 > 知识库问答 >
问题:

面向上下文的运行时CDI限定符(HK2,Guice)

周子平
2023-03-14
// I would want to turn this...
public final class Handler
{ 
  private final Session session;
   
  @Inject   
  public Handler(@Named("Database") final Session session)
  {
    this.session = session;
  }
  ...
}

// into something like this...
public final class Handler
{
  private final Session session;
    
  @Inject
  public Handler(final Session session)
  {
    this.session = session;
  }
}

// where "session" is injected based on some previous context value ("Database")
// or something to that effect.

共有1个答案

薛祯
2023-03-14

我最后使用了HK2中的一个名为Operations(指向文档的链接)的功能。它允许HK2的用户定义自定义范围,并将其管理为“操作”。您可以在HK2的github项目中找到如何使用该功能的更详细示例:operations example。

这是一个简化的例子,说明了我最终是如何使用这个特性来基于上下文或在本例中是“范围”来注入东西的。

下面是一些几乎可以工作的伪代码来演示我的用法:

// Create the custom scope annotation.
@Scope
@Proxiable(proxyForSameScope = false)
@Documented
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface BatchScope
{
  public static final BatchScope INSTANCE = new BatchScopeEnvoy();
}


final class BatchScopeEnvoy extends AnnotationLiteral<BatchScope> implements BatchScope
{
  private static final long serialVersionUID = 938233179310254573L;
}


// Create a context used by the HK2 operation feature.
@Singleton
public final class BatchScopeContext extends OperationContext<BatchScope>
{
  @Override
  public Class<? extends Annotation> getScope()
  {
    return BatchScope.class;
  }
}


// Create a class that holds your custom scope data/context.
public final class BatchScopeRuntime
{
   // ... Arbitrary runtime data here ...
     
     public SomeData getData()
     {
       return this.data;
     }
}


// Create a factory that serves up something you want to inject from a custom scope.
@Singleton
public final class DataFactory implements Factory<SomeData>
{
  private final OperationManager operations;

  @Inject
  public BatchInfoFactory(final OperationManager operations)
  {
    Sentinel.assertIsNotNull(operations);

    this.operations = operations;
  }


  // The @BatchScope on the provide() method indicates that objects returned 
  // from this factory are in the "BatchScope".
  @Override
  @BatchScope
  public IBatchInfo provide()
  {
    final OperationHandle handle = this.operations.getCurrentOperation(BatchScope.INSTANCE);
    final BatchScopeRuntime runtime = (BatchScopeRuntime)handle.getOperationData();

    return runtime.getData();
  }

  @Override
  public void dispose(final IBatchInfo instance)
  {
    // Do nothing.
  }
}


// Setup the injector.
public static ServiceLocator createInjector(final String name)
{
    final ServiceLocator injector = ServiceLocatorFactory.getInstance().create(name);

    ServiceLocatorUtilities.bind(
      injector,
      new AbstractBinder()
      {
        @Override
        protected void configure()
        {
           // This creates a "Singleton" factory that provides
           // "SomeData" instances at "BatchScope".
           bindFactory(DataFactory.class, Singleton.class)
            .to(SomeData.class)
            .in(BatchScope.class);
        }
      }
        
    return injector;
}


// Create a class that needs something in the custom scope.
public final class Foo
{
  @Inject
  public Foo(final SomeData data)
  {
    System.out.printf("I got: %s%n", data);
  }
}   


// Usage: how to manage the scopes using the operations feature.
final SomeData data = ... // get some data
final BatchScopeRuntime runtime = new BatchScopeRuntime(data); // Setup the runtime information.

// Create an operation handle for the custom scope and associate the custom data with it.
final ServiceLocator injector = createInjector("test");
ServiceLocatorUtilities.addClasses(injector, BatchScopeContext.class, Foo.class);
final OperationManager operations = injector.getService(OperationManager.class);
final OperationHandle<BatchScope> batchScope = operations.createAndStartOperation(BatchScope.INSTANCE);

// Operation/scope is now associated with the current thread.           
batchScope.setOperationData(runtime);

// Foo will now be injected with: "data" from above.
final Foo foo = injector.getService(Foo.class);

// Do some work...

// Close the operation (make it go out of scope) on the current thread.
batchScope.closeOperation();
 类似资料:
  • 作为CDI的新手,我想知道替代方案和限定符之间的实际区别。 在焊缝参考中,它指出: 4.3. 限定符注释 如果我们有多个实现特定bean类型的bean,注入点可以使用限定符注释精确指定应该注入哪个bean。 但在解释替代方案时,据说: 4.7.备选方案 替代方案是bean,其实现特定于特定的客户端模块或部署场景。 如果我理解正确的话,@Qualifier定义了目标bean的哪些实现被注入到注入点。

  • 我试图找出CDI和适合我需要的最佳方法。我有一个与普通tcp通信交互的服务()。现在这个服务有一些地方需要通知某人发生了什么事情。对于这些信息,我有接口,需要将其CDI注入到正确的实现中。另一个问题是服务本身被注入一个作业()中,该作业定期执行并调用服务来完成任务。这意味着服务将多次存在。每个都有它处理的另一个tcp连接,并且有另一个需要在接口中注入另一个驱动程序/协议的设备。 让我展示参与此场景

  • 问题内容: 我试图了解下限和上限通配符的行为。 尝试编译以下代码时遇到问题。 为了弄清楚问题,我还尝试了下限通配符。幸运的是或不幸的是,代码可以很好地编译,但是却造成了很多混乱。 有人可以解释一下这两个代码段如何工作。如果有人可以提供其他示例/链接,那就太好了。 如果我在上面做错了什么,请纠正我。 提前致谢。 问题答案: 表示“未知类型”。 表示某种对象的集合。此“某种类型”可以是作为其子类或自身

  • 我需要根据应用程序执行的环境(开发、测试、生产等)改变JDBC连接的注入方式。新环境的添加必须易于处理。因此,考虑到佩莱格里尼对以下问题的解决方案,我试图实施这种行为: 多个CDI配置文件(devel,beta,qa,生产)在一个战争? 注射点是这样的: 我有两个连接工厂: ConnectionFactory:用于测试、验收和生产环境; ProxyConnectionFactory:仅适用于开发环

  • 假设有一个SessionFactory的生产者(举个例子): 不,我可以这样使用我的数据库对象: 到目前为止,一切都很好。因此,让我们假设这些东西是在一个框架中实现的,并且将被几个应用程序使用。 现在,一个应用程序决定使用另一个SessionFactory,因此它实现了自己的生产者和一个限定符:

  • 我有一个平面文件连接,它在SSIS包中加载文本文件。Visual Studio有时坚持在连接管理器上添加文本限定符,即使我删除了它。当添加此文本限定符时,将跳过文件中的最后一条记录,因此会导致问题。我需要一种方法来确保文件总是工作,有或没有这个限定符。既然我是以编程方式创建这些文件,那么它需要如何结束才能使限定符不影响它呢?我尝试用\r\n结束文件,但似乎没有解决问题。