如何访问对象而不将其作为参数传递?

Posted

技术标签:

【中文标题】如何访问对象而不将其作为参数传递?【英文标题】:How to access object without passing it as parameter? 【发布时间】:2021-10-30 14:52:50 【问题描述】:

有没有办法自动装配需要经常重新实例化的对象?

我正在使用 Netflix 的 DGS + spring boot 框架,并且基本上将用户身份验证详细信息存储在为每个请求创建的自定义上下文中。由于需要大量重构,我试图避免在方法签名中添加上下文。

例如

public Result dataFetcher(DataFetchingEnvironment dfe) 
   

   // this context contains user details which is used for authorization
   // instantiated for every request
   setRolesInContext(dfe);
   MyCustomContext context = DgsContext.getCustomContext(dfe);

   // trying to avoid adding context as an extra param e.g. dataFetcherHelper(context)
   dataFetcherHelper(); // this calls other helper methods from other classes

我正在考虑使用外观模式,但这不是线程安全的。基本上自动装配RequestContextHolder,并在每次初始化新上下文时调用setRequestContext

@Component
@NoArgsConstructor
@Getter
@Setter
public class RequestContextHolder 
    private RequestContext requestContext;

【问题讨论】:

【参考方案1】:

我不确定你的问题:

有没有办法自动装配需要经常重新实例化的对象?

与您在问题中提出的用例有关...

从问题看来,如果您不想向方法添加参数以通过流。

这仅适用于“每个请求线程”模型,不适用于反应式系统以及在后端实现业务逻辑时维护不同线程池并切换线程的复杂情况:

因此,要在您建议的上下文持有者中实现“线程安全”,您可以使用:

@Configuration
public class MyConfig 
  @Bean
  public ThreadLocal<MyCustomContext> ctxHolder() 
     return new ThreadLocal<>();
  


再一次,如果您使用的是线程每请求模型,您可以:

@Component
public class DataFetcherInterceptor 
   @Autowired
   private ThreadLocal<MyCustomContext> ctxHolder;

   public Result dataFetcher(DataFetchingEnvironment dfe) 
   

      // this context contains user details which is used for authorization
      // instantiated for every request
      setRolesInContext(dfe);
      MyCustomContext context = DgsContext.getCustomContext(dfe);
      ctxHolder.set(context);
      dataFetcherHelper(); 
   

dataFetcherHelper 或通常在任何需要访问上下文的方法中,您都可以:

public class SomeService 
   @Autowired ThreadLocal<MyCustomContext> ctxHolder;

   public void dataFetcherHelper() 
      MyCustomContext ctx = ctxHolder.get();
   

现在,我看到 dataFetcherHelper 只是您从这个“拦截器”类中调用的一个方法,在这种情况下它是一个矫枉过正的方法,但我假设,你的意图是这实际上是一个属于另一个类,它可能是不同类的调用链中的一个元素。对于这些情况,这可能是一个可行的解决方案。

【讨论】:

感谢马克的周到回答,这绝对给了我一个良好的开端。我最终发现 Spring bean 可以限定为 Web 感知应用程序的请求级别,这意味着每个 bean 可以在每个请求中拥有自己的实例。 docs.spring.io/spring-framework/docs/current/reference/html/…

以上是关于如何访问对象而不将其作为参数传递?的主要内容,如果未能解决你的问题,请参考以下文章

阿帕奇火花。 UDF 列基于另一列而不将其名称作为参数传递。

如何将列表的所有元素作为函数的参数传递而不将列表作为参数传递

在 ApiController 操作中获取当前用户,而不将用户 ID 作为参数传递

CMAKE 使用环境变量而不将它们作为命令行参数传递?

如何自动将用户信息传递给 Bot Framework 对话实例,而不将其作为显式消息发布在聊天窗口中?

如何从 Terraform 输出中传递值而不将其放入 tfvars 文件中