如何解决使用Kotlin解决Spring Boot Rest Controller中的单例?

我是Spring和Spring Boot的新手,我以不同的方式尝试解决Bean。在我的示例中,我有一个始终应该是单例的Bean。令我惊讶的是,似乎有一种方法可以将这个bean解析为“原型”。

有人可以向我解释为什么在方法showSingletonBeans的签名中解析时它不是单例吗?

@SpringBootApplication
class DemoApplication

fun main(args: Array<String>) {
    runApplication<DemoApplication>(*args)
}

@Service("stackSingletonBean")
// @Scope("singleton")
class MySingletonBean {
    init {
        println("Created MySingletonBean " + this.hashCode())
    }
}

@RestController
class MyController {

    @Autowired
    // @Qualifier("singletonBean")
    lateinit var memberSingletonBean: MySingletonBean

    @Autowired
    lateinit var singeltonFactory: ObjectFactory<MySingletonBean>

    fun buildSingleton() : MySingletonBean {
        return singeltonFactory.`object`
    }

    @Lookup
    fun getSingletonInstance() : MySingletonBean? {
        return null
    }

    @GetMapping("/")
    fun showSingletonBeans(@Autowired stackSingletonBean: MySingletonBean) {
        println("member " + memberSingletonBean.hashCode() )
        println("stack " + stackSingletonBean.hashCode())
        println("lookup:" + getSingletonInstance().hashCode())
        println("factory: " + buildSingleton().hashCode())
    }
}

日志如下:

2020-08-13 18:44:32.604  INFO 172175 --- [           main] com.example.demo.DemoApplicationKt       : No active profile set,falling back to default profiles: default
2020-08-13 18:44:33.118  INFO 172175 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2020-08-13 18:44:33.124  INFO 172175 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2020-08-13 18:44:33.124  INFO 172175 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.37]
2020-08-13 18:44:33.164  INFO 172175 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2020-08-13 18:44:33.164  INFO 172175 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 528 ms
Created MySingletonBean 1747702724
2020-08-13 18:44:33.286  INFO 172175 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-08-13 18:44:33.372  INFO 172175 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-08-13 18:44:33.379  INFO 172175 --- [           main] com.example.demo.DemoApplicationKt       : Started DemoApplicationKt in 1.011 seconds (JVM running for 1.24)
2020-08-13 18:44:37.341  INFO 172175 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring dispatcherServlet 'dispatcherServlet'
2020-08-13 18:44:37.341  INFO 172175 --- [nio-8080-exec-1] o.s.web.servlet.dispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2020-08-13 18:44:37.344  INFO 172175 --- [nio-8080-exec-1] o.s.web.servlet.dispatcherServlet        : Completed initialization in 3 ms
Created MySingletonBean 562566586
member 1747702724
stack 562566586
lookup:1747702724
factory: 1747702724
Created MySingletonBean 389331797
member 1747702724
stack 389331797
lookup:1747702724
factory: 1747702724

解决方法

解析控制器方法参数实际上是完全不同的机制。它与依赖项注入和@Autowired批注无关:批注可以删除,并且不会改变行为。

尽管从Spring Framework 5.0开始,@ Autowired在技术上可以在单个方法或构造函数参数上声明,但是该框架的大多数部分都忽略了此类声明。积极支持自动装配参数的核心Spring框架的唯一部分是spring-test模块中的JUnit Jupiter支持(有关详细信息,请参见TestContext框架参考文档)。
https://docs.spring.io/

在您的情况下,stackSingletonBeanModelAttributeMethodArgumentResolver实例化。它不知道@Service注释也不知道其范围:它只是在每个请求上使用默认构造函数。

模型属性源自模型,或使用默认构造函数创建,然后添加到模型中。

请注意,@ ModelAttribute的使用是可选的,例如用于设置其属性。默认情况下,任何不是简单值类型(由BeanUtils#isSimpleProperty确定)且未被其他任何参数解析器解析的参数都将被视为使用@ModelAttribute注释。 Web on Reactive Stack