Custom InjectableContext cannot differ between two injection points within the same bean in Quarkus

huangapple go评论72阅读模式
英文:

Custom InjectableContext cannot differ between two injection points within the same bean in Quarkus

问题

I try to implement a @TenantScope which can be used for stateful beans rather than using a nested map. For this I am implementing a io.quarkus.arc.InjectableContext.

我尝试实现一个@TenantScope,用于管理有状态的bean,而不是使用嵌套的映射。为此,我正在实现一个io.quarkus.arc.InjectableContext

I have it working so far, except if I have two injection points of the same type. My implementation for the two get(...) methods looks like this::

到目前为止,我的实现已经能够正常工作,除非我有两个相同类型的注入点。我的两个get(...)方法的实现如下:

@Override
public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) {
    String tenantId = getTenantIdFromContext();
    Map<String, ContextInstanceHandle<?>> tenantMap = contextualMap.computeIfAbsent(contextual, c -> new HashMap<>());
    @SuppressWarnings("unchecked")
    ContextInstanceHandle<T> contextInstanceHandle =
            (ContextInstanceHandle<T>) tenantMap.computeIfAbsent(tenantId, t -> {
                if (creationalContext == null) {
                    return null;
                }
                T createdInstance = contextual.create(creationalContext);
                return new ContextInstanceHandleImpl<T>(
                        (InjectableBean<T>) contextual, createdInstance, creationalContext);
            });
    return contextInstanceHandle.get();
}

@SuppressWarnings("unchecked")
@Override
public <T> T get(Contextual<T> contextual) {
    String tenantId = getTenantIdFromContext();
    if(!contextualMap.containsKey(contextual) || !contextualMap.get(contextual).containsKey(tenantId)){
        return null;
    }
    return ((ContextInstanceHandle<T>) contextualMap.get(contextual).get(tenantId)).get();
}

Assume this bean

假设这个Bean

@TenantScoped
class MyTenantScopedQueue(){...}

My custom context behaves as expected when I have a single injection point of a @TenantScoped type in a bean. Depending on the tenantId of my context, I get the specific instance. As soon as I have two injection points I run into a problem:

当我在Bean中有一个@TenantScoped类型的单一注入点时,我的自定义上下文表现如预期。根据我的上下文的tenantId,我得到特定的实例。但是,一旦我有两个注入点,我就遇到了问题:

class MyBean() {

@Inject
MyTenantScopedQueue queue;
@Inject
MyTenantScopedQueue queueForOtherStuff;

...
}

It seems that Contextual<T> does not hold enough information to differ between these two injection points resulting in having the same instance injected twice. How can I implement my InjectableContext so I do get different instances for each injection point?

看起来Contextual<T>似乎没有足够的信息来区分这两个注入点,导致相同的实例被注入两次。我如何实现我的InjectableContext,以便每个注入点都得到不同的实例?

英文:

I try to implement a @TenantScope which can be used for stateful beans rather than using a nested map. For this I am implementing a io.quarkus.arc.InjectableContext.

I have it working so far, except if I have two injection points of the same type. My implementation for the two get(...) methods looks like this::

@Override
public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) {
    String tenantId = getTenantIdFromContex();
    Map<String, ContextInstanceHandle<?>> tenantMap = contextualMap.computeIfAbsent(contextual, c -> new HashMap<>());
    @SuppressWarnings("unchecked")
    ContextInstanceHandle<T> contextInstanceHandle =
            (ContextInstanceHandle<T>) tenantMap.computeIfAbsent(tenantId, t -> {
                if (creationalContext == null) {
                    return null;
                }
                T createdInstance = contextual.create(creationalContext);
                return new ContextInstanceHandleImpl<T>(
                        (InjectableBean<T>) contextual, createdInstance, creationalContext);
            });
    return contextInstanceHandle.get();
}

@SuppressWarnings("unchecked")
@Override
public <T> T get(Contextual<T> contextual) {
    String tenantId = getTenantIdFromContex();
    if(!contextualMap.containsKey(contextual) || !contextualMap.get(contextual).containsKey(tenantId)){
        return null;
    }
    return ((ContextInstanceHandle<T>) contextualMap.get(contextual).get(tenantId)).get();
}

Assume this bean

@TenantScoped
class MyTenantScopedQueue(){...}

My custom context behaves as expected when I have a single injection point of a @TenantScoped type in a bean. Depending on the tenantId of my context, I get the specific instance. As soon as I have two injection points I run into a problem:

class MyBean() {

@Inject
MyTenantScopedQueue queue;
@Inject
MyTenantScopedQueue queueForOtherStuff;

...
}

It seems that Contextual<T> does not hold enough information to differ between this two injection points resulting in having same instance injected twice. How can I implement my InjectableContext so I do get different instances for each injection point?

答案1

得分: 0

@TenantScoped 是一个正常的范围吗?如果是的话,那么被注入的 MyTenantScopedQueue(它是一个客户端代理)必须首先获取活动的上下文对象,然后调用 Context.get(),最后委托给底层的 bean 实例。而且你的上下文实现必须确保对于给定的 bean,与当前线程关联的确切实例只有一个。

现在,这两个注入点都由同一个 Bean 满足。这意味着如果你从同一个线程上调用 queuequeueForOtherStuff 上的方法,那么两个调用都将委托给相同的 bean 实例。

如果范围不是正常的,即没有用 @jakarta.enterprise.context.NormalScope 注解,而是用 @jakarta.inject.Scope 注解,那么行为是未定义的(由你决定)。

英文:

Is the @TenantScoped a normal scope? If so then the injected MyTenantScopedQueue (which is a client proxy) must obtain the active context object first, then call Context.get() and finally delegate to the underlying bean instance. And your context implementation must ensure that there is exactly one instance for a given bean associated with the current thread.

Now both injection points are satisfied by the same Bean. Which means that if you invoke a method upon queue and queueForOtherStuff from the same thread then both invocations will delegate to the same bean instance.

If the scope is not normal, i.e. not annotated with @jakarta.enterprise.context.NormalScope but with @jakarta.inject.Scope, then the behavior is undefined (up to you ;-).

huangapple
  • 本文由 发表于 2023年5月11日 05:19:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76222626.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定