如何将自定义范围/上下文(JobScoped - 自定义CDI范围)特定实例放入请求以使其可注入? [英] How to put in custom scope/context (JobScoped - custom CDI scope) particular instance from request to make it injectable?

查看:160
本文介绍了如何将自定义范围/上下文(JobScoped - 自定义CDI范围)特定实例放入请求以使其可注入?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简而言之,我想从rest请求中放入自定义范围的Configuration类的特定实例。
主要问题是,定制范围(从JobScoped 工作开始后,https://jberet.gitbooks.io/jberet-user-guide/content/custom_cdi_scopes/index.html )是合格的。
我知道有可能在启动作业时添加属性,但是我的Configuration类会聚集很多配置而且它很复杂
因此将这些文件转换为Properties类会非常不舒服。

Saying in a nutshell I would like to put in custom scope particular instance of Configuration class from rest request. Main problem is that custom scope (JobScoped from JBeret https://jberet.gitbooks.io/jberet-user-guide/content/custom_cdi_scopes/index.html) is eligable after job starts. I know that there is possibility to add properties when starting job but my Configuration class agregates a lot of configurations and it's quite complicated so it would by very uncomfortable to convert this files to Properties class.

以下详细信息:

这是休息请求伪代码:

@Path("/job")
public class RunJob {

@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Path("/start")
public String startJob(@FormDataParam("file") InputStream uploadedInputStream) {
    JobOperatorImpl jobOperator = (JobOperatorImpl) BatchRuntime.getJobOperator();

    Configuration config = new Configuration(uploadedInputStream);
    Properties properties = new Properties();
    jobOperator.start(job, properties);
}

我想要实现的是在Job的上下文中注入一些配置文件下面:

What I wanted to achieve is to Inject some configuration files in context of Job like below:

public class MyReader implements ItemReader {

@Inject
private Configuration configFile;
}

配置类如下所示:

@JobScoped
public class Configuration {
 // some flags, methods etc
}

我已经阅读了Instance,Provider但在我的情况下不知道如何使用它们。
实际上我认为不可能使用它们,因为作业是由它们的名称标识的,它是动态
并且在运行时已知。

I've read about Instance, Provider but don't know how to use them in my case. In fact I think it's impossible to use them because the jobs are identified by their name which is dynamic and known at runtime.

与此同时,我发现了类似的情况:
我可以创建一个请求范围的对象并从任何地方访问它,并避免在JAX-RS中作为参数传递它吗?

Meanwhile I found similar situation to mine: Can I create a request-scoped object and access it from anywhere, and avoid passing it around as a parameter in JAX-RS?

然后发生缺少上下文的问题。 Job启动时有JobScoped上下文。
根据以上溶液我已经注释的配置作为RequestScoped,然后我接收到的:

But then occurs problem with missing context. When Job starts there is JobScoped context. According to above solution I had annotated Configuration as RequestScoped, then i received:

org.jboss.weld.context.ContextNotActiveException :WELD-001303:对于范围类型javax.enterprise.context.RequestScoped
。在
org.jboss.weld.manager.BeanManagerImpl.getContext否
活性上下文(BeanManagerImpl.java:689)
at
org.jboss.weld.bean.ContextualInstanceStrategy $ DefaultContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:90)
at
org.jboss.weld.bean.ContextualInstanceStrategy $ CachingContextualInstanceStrategy.getIfExists (ContextualInstanceStrategy.java:165)
。在
org.jboss.weld.bean.ContextualInstance.getIfExists(ContextualInstance.java:63)
。在
org.jboss.weld.bean .proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:83)
at
org.jboss.weld.bean.proxy.ProxyMethodHandler.getInstance(ProxyMethodHandler.java:125)
Configuration $ Proxy $ _ $$ _ WeldClientProxy.toString(Unknown Source)

org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.RequestScoped at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:689) at org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:90) at org.jboss.weld.bean.ContextualInstanceStrategy$CachingContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:165) at org.jboss.weld.bean.ContextualInstance.getIfExists(ContextualInstance.java:63) at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:83) at org.jboss.weld.bean.proxy.ProxyMethodHandler.getInstance(ProxyMethodHandler.java:125) Configuration$Proxy$_$$_WeldClientProxy.toString(Unknown Source)


推荐答案

我认为这个问题由几部分组成:

I think this question consists of several parts:


  1. 如何将值注入批处理作业?

  2. 如何种子上下文基于批处理作业的值?

  3. 如何在批处理作业中输入RequestScope?

  4. 如何创建自定义范围?

  5. 如何输入自定义范围?

  6. 如何在自定义范围内播种值?

  1. How to inject values into batch jobs?
  2. How to seed context based values to batch jobs?
  3. How to enter the RequestScope in a batch job?
  4. How to create a custom scope?
  5. How to enter a custom scope?
  6. How to seed a value in a custom scope?

我会尝试回答所有问题,但请记住,我最近才开始使用CDI / Weld,并且没有JBeret的经验。

I will try to answer all individual questions, but keep in mind that I've only very recently started using CDI/Weld, and have no experience with JBeret.

我添加此问题的原因是因为我认为配置可能不需要是一个范围的实体。如果配置没有特定于范围的内容,则可以是 @Singleton @Stateless 。例如,从配置文件,资源或环境变量中考虑,这些变量在运行时不会改变。可以使用常规 @Inject 字段将非范围(或单例范围)依赖项注入到小批量中,而无需 @JobScoped 注释。

The reason I am adding this question, is because I think Configuration may not need to be a scoped entity. If Configuration has nothing specific to the scope, it could be @Singleton or @Stateless as well. Think for example from configuration files, resources, or environment variables, that will not change on runtime. Non-scoped (or Singleton-scoped) dependencies can be injected into batchlets just fine, using regular @Inject fields, without any need for a @JobScoped annotation.

那么如果实际值取决于上下文并且无法注入 @Singleton 时尚?基于JBeret 文档,最好是通过属性传递所有配置。然后可以从 JobContext 中读取这些内容,或使用 @BatchProperty 注释进行注入。这仅适用于可从String进行序列化的预定义类型列表。

So what if the actual value depends on the context and cannot be injected in a @Singleton fashion? Based from the JBeret documentation, it is preferred to pass all configuration by Properties. These can then be read from the JobContext, or injected using the @BatchProperty annotation. This only works for a predefined list of types that are serialisable from a String.

@Named
public class MyBatchlet extends AbstractBatchlet {

    @Inject
    @BatchProperty(name = "number")
    int number;

}



3。如何在批处理作业中输入 @RequestScope



我认为你不应该这样做。 @RequestScope 仅用于请求。如果依赖于 @RequestScope 的依赖项应该可以在请求之外访问,请考虑引入自定义范围。

3. How to enter the @RequestScope in a batch job?

I think you shouldn't. The @RequestScope is for requests solely. If you have dependencies dependent on @RequestScope that should be accessible outside of a request, consider to introduce a custom scope.

如果你真的需要以编程方式输入 @RequestScope ,你可以为它定义自己的上下文并输入该上下文(参见下面的第4部分) )或默认输入上下文,如中所述丹·海伍德(Dan Haywood)试图进入Java SE中的 @RequestScope

If you really need to enter the @RequestScope programatically, you can define your own context for it and enter that context (see part 4 below) or enter the context by default, as addressed in this blogpost by Dan Haywood, in his attempt to get into the @RequestScope in Java SE.



4。如何创建自定义范围?



创建自定义范围相当容易。但是,自定义范围需要范围上下文的实现。我发现这在文档中有点不清楚。幸运的是,有一个图书馆微观图书馆。对于此示例,您只需要 microscoped-core 依赖项,该依赖项提供在其自定义中使用的 ScopeContext 实现范围。我们将使用 ScopeContext 作为我们的简单范围。

4. How to create a custom scope?

It is fairly easy to create a custom scope. A custom scope however requires an implementation for the scope context. I found this to be a little unclear in the documentation. Luckily there is the library microscoped library. For this example, you only need the microscoped-core dependency, which provides a ScopeContext implementation that is used in their custom scopes. We will use that ScopeContext for our simple scope as well.

首先我们必须创建范围注释:

First we have to create the Scope annotation:

@Documented
@Scope
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
public @interface CustomScoped {}

其次,我们必须创建一个扩展名:

Secondly, we have to create an extension:

public class CustomScopedExtension implements Extension, Serializable {

    public void addScope(@Observes final BeforeBeanDiscovery event) {
        event.addScope(CustomScoped, true, false);
    }

    public void registerContext(@Observes final AfterBeanDiscovery event) {
        event.addContext(new ScopeContext<>(CustomScoped.class));
    }

}

请注意,我们正在使用来自microscoped的ScopeContext。此外,您应该通过将完整的类名添加到 META-INF / services / javax.enterprise.inject.spi.Extension`来注册您的扩展名。

Note that we're using the ScopeContext from microscoped here. Furthermore, you should register your extension by adding the full classname toMETA-INF/services/javax.enterprise.inject.spi.Extension`.

现在我们需要输入我们的范围。我们可以使用一些代码执行此操作,例如,您可以在Web Filter 或方法拦截器中放置代码。代码使用 BeanManager 实例,可以使用 @Inject 获得:

Now we need to enter our scope. We can do this with a little bit of code, that you can place for example in a web Filter or method interceptor. The code uses an BeanManager instance, which can be obtained with @Inject:

ScopeContext<?> context = (ScopeContext<?>) beanManager.getContext(CustomScoped.class);
context.enter(key);
try {
     // continue computation
} finally {
    context.destroy(key);
}



6。如何在自定义范围内设置一个值?



我一直在问自己同样的问题,这就是我提出的解决方案。另请参阅关于如何从自定义Weld CDI范围正确播种的问题:种子值焊接CDI自定义范围。我确实为您的问题找到了解决方法:

6. How to seed a value in a custom scope?

I have been asking myself the very same question, and this is the solution I came up with. See also my question on how to properly seed from custom Weld CDI scopes: Seed value in Weld CDI custom scope . I do have a workaround for your issue though:

@Singleton
public class ConfigurationProducer {

    private final InheritableThreadLocal<Configuration>  threadLocalConfiguration =
    new InheritableThreadLocal<>();

    @Produces
    @ActiveDataSet
    public ConfigurationConfiguration() {
       return threadLocalConfiguration.get()
    }

    public void setConfiguration(Configuration configuration) {
         threadLocalConfiguration.set(configuration);
    }    

}

现在来自你上面写的拦截器,你可以注入 ConfigurationProducer 并使用 ConfigurationProducer #setConfiguration(配置)来设置配置表示当前线程。我仍然在这里寻找更好的选择。

Now from your the interceptor written above, you can inject ConfigurationProducer and use ConfigurationProducer #setConfiguration(Configuration) to set the Configuration for the current thread. I am still looking for better options here.

这篇关于如何将自定义范围/上下文(JobScoped - 自定义CDI范围)特定实例放入请求以使其可注入?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆