Spring Boot请求范围的Bean自动装配未填充。

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

Spring Boot Request Scoped Beans Autowired not Populated

问题

我对Spring Boot还很陌生,我只想使用它的依赖注入,而不是所有的框架,只是一些框架。我知道有其他替代方案来实现这个功能,但我想更多地了解Spring。

我正在尝试创建一个请求范围的bean,并使用常规的依赖注入来填充它。我的计划是创建一个User对象,我可以填充它以保存一些自定义的业务细节,这样可以轻松访问,使代码更清晰。

@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
class MyBean {
  @Autowired
  lateinit var req: HttpServletRequest

  @Autowired
  lateinit var env: Environment

  @PostConstruct
  fun pc() {
    println("I am constructed $this, $req, $env")
  }

  var a = 3
}
@RestController
class MyController {
    @GetMapping("/api/xyz")
    fun login(m: MyBean): Int {
        println("new bean m")
        return m.a
    }
}

每次我访问该端点时,我看到新的对象被实例化。但是内部的依赖关系没有被自动装配,它们始终为null。我做错了什么?我需要编写一个过滤器吗?但是我怎么知道如何找到所有需要初始化该bean的端点?如果我删除请求范围,变量会被初始化。

英文:

I'm new to Spring Boot, I only like to use its dependency injection, not all its opinionated frameworks but some. I know there are other alternatives for this functionality, but I would like to learn more Spring.

I am trying to have a request scoped bean and populate it with regular dependency injection. My plan is to have some User object that I can populate hold some custom business details that is easy to access that makes code clean.

@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
class MyBean {
  @Autowired
  lateinit var req: HttpServletRequest

  @Autowired
  lateinit var env: Environment

  @PostConstruct
  fun pc() {
    println("I am constructed $this, $req, $env")
  }

  var a = 3
}


@RestController
class MyController {
    @GetMapping("/api/xyz")
    fun login(m: MyBean): Int {
        println("new bean m")
        return m.a
    }
}

Every time I hit that endpoint, I see new objects are instantiated. However the inner dependencies are not autowired, they are always null. What am I doing wrong? Do I need to write a filter? But how would I know how to find all the endpoints that needs that bean to be initialized? If, I remove the request scope the variables are initialized.

答案1

得分: 1

RestControllers 就像 ComponentsServices 一样是bean。所以在所有这些情况下,你应该以相同的方式处理注入的依赖项。

谈到你要添加的示例,bean 不应该是实际端点映射的参数。请求特定信息,如标头、路径变量或负载主体,适用于端点映射方法参数。

对于你的类 MyBean 的 bean 实例,你应该更倾向于直接注入成员变量或通过你的 MyController 构造函数注入(其中基于构造函数的注入是推荐的方法)。

当在 MyController 的构造函数中注入你的 MyBean(它是 RequestScoped)时,请不要感到困惑:这是完全有意的,并且有效。Spring 实际上会注入一个代理实例,一旦请求到达控制器调用,它将解析为请求特定的实例。

英文:

RestControllers are beans like Components or Services. So in all of these you should deal with injected dependencies the same way.

Coming to the example you were adding, beans should not be parameters of actual endpoint mappings. Asking for request specific information like headers, path variables or the payload body are candidates for endpoint mapping method arguments.

For a bean instance of your class MyBean you should rather use a member variable injected directly or via the constructor of your MyController (where constructor based injection is the recommended approach).

Don't be confused when injecting your MyBean which is RequestScoped in the constructor of MyController: this is totally intended and works. Spring actually injects a proxy instance that will resolve to the request specific instance once your request is reaching the controller invocation.

huangapple
  • 本文由 发表于 2020年8月4日 02:49:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/63235262.html
匿名

发表评论

匿名网友

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

确定