英文:
Call singleton class in spring boot rest api controller
问题
我是Spring框架的新手。我必须使用Spring Boot,并创建一个如下所示的REST控制器:
@RestController
public class StatisticsController {
private TransactionCache transactionCache;
public StatisticsController(TransactionCache transactionCache) {
this.transactionCache = transactionCache;
}
@PostMapping("/tick")
public ResponseEntity<Object> addInstrumentTransaction(@Valid @RequestBody InstrumentTransaction instrumentTransaction) {
transactionCache.addTransaction(instrumentTransaction);
return new ResponseEntity<>(HttpStatus.CREATED);
}
}
我还有一个需要成为单例的类:
@Component
public class TransactionStatisticsCacheImpl implements TransactionCache {
private static TransactionStatisticsCacheImpl instance;
public static TransactionStatisticsCacheImpl getInstance(){
if(Objects.isNull(instance)){
synchronized (TransactionStatisticsCacheImpl.class) {
if(Objects.isNull(instance)){
instance = new TransactionStatisticsCacheImpl();
}
}
}
return instance;
}
private TransactionStatisticsCacheImpl() {}
}
我想知道在我的REST控制器中调用这个单例类的正确方式。我知道在Spring中,默认情况下,bean的作用域是单例的。这是否是在REST控制器中调用单例类的正确方式?
@RestController
public class StatisticsController {
private TransactionCache transactionCache;
public StatisticsController(TransactionCache transactionCache) {
this.transactionCache = transactionCache;
}
@PostMapping("/tick")
public ResponseEntity<Object> addInstrumentTransaction(@Valid @RequestBody InstrumentTransaction instrumentTransaction) {
transactionCache.addTransaction(instrumentTransaction);
return new ResponseEntity<>(HttpStatus.CREATED);
}
}
还是应该使用getInstance()
方法调用它?另外,我们是否需要在TransactionStatisticsCacheImpl
类中显式地有getInstance
方法?
英文:
I am new to spring framework. I have to use spring boot and have a rest controller as below :-
@RestController
public class StatisticsController {
private TransactionCache transactionCache;
public StatisticsController(TransactionCache transactionCache) {
this.transactionCache = transactionCache;
}
@PostMapping("/tick")
public ResponseEntity<Object> addInstrumentTransaction(@Valid @RequestBody InstrumentTransaction instrumentTransaction) {
transactionCache.addTransaction(instrumentTransaction);
return new ResponseEntity<>(HttpStatus.CREATED);
}
and I have a class which needs to be singleton :-
@Component
public class TransactionStatisticsCacheImpl implements TransactionCache {
private static TransactionStatisticsCacheImpl instance;
public static TransactionStatisticsCacheImpl getInstance(){
if(Objects.isNull(instance)){
synchronized (TransactionStatisticsCacheImpl.class) {
if(Objects.isNull(instance)){
instance = new TransactionStatisticsCacheImpl();
}
}
}
return instance;
}
private TransactionStatisticsCacheImpl() {}
I want to know the correct way to call this singleton class in my rest controller. I know that by default the scope of a bean in spring is singleton. Is this the correct way to call the singleton class in rest controller?
@RestController
public class StatisticsController {
private TransactionCache transactionCache;
public StatisticsController(TransactionCache transactionCache) {
this.transactionCache = transactionCache;
}
@PostMapping("/tick")
public ResponseEntity<Object> addInstrumentTransaction(@Valid @RequestBody InstrumentTransaction instrumentTransaction) {
transactionCache.addTransaction(instrumentTransaction);
return new ResponseEntity<>(HttpStatus.CREATED);
}
or
We need to call it using the getInstance() method? Also do we need to explicitly have the getInstance method in the TransactionStatisticsCacheImpl class?
答案1
得分: 3
容器注入的主要优势之一是,您可以在不会出现“硬”单例(例如难以进行测试的问题)的严重问题的情况下,获得单例语义的好处。摆脱getInstance
手动处理的繁琐步骤,让 Spring 来确保创建并在上下文中使用单一实例。
英文:
One of the major advantages of container injection is that you can get the benefits of singleton semantics without all the serious problems of "hard" singletons (such as difficulty testing). Get rid of the getInstance
manual business and let Spring take care of ensuring that a single instance is created and used for the context.
答案2
得分: 0
仅供澄清:默认情况下,Spring IOC 容器每个 bean 定义只会创建一个实例,除非您使用 @Scope
注释另有指定。但如果您使用 getInstance()
创建实例,则 bean 的预处理器和后处理器将无法在该 bean 定义上正常工作。而且,您可以使用 @Autowired
注释根据需要注入 bean 定义,如果针对同一定义有不同的实现,您可以使用 @Qualifier
注释指定您需要注入的实现。或者,您可以使用构造函数注入根据需要注入您的 bean 定义,而无需像此处所述自动进行连接 Spring @Autowire on Properties vs Constructor
英文:
Just for clarification: By default, the spring IOC container will create only one instance per bean definition, unless if you specified otherwise using the @Scope
stereotype. But if you create an instance using getInstance()
the bean pre-processors and post-processors will not work correctly on that bean definition. And also you can use the @Autowired
stereotype to inject a bean definition as needed and if you have different implementations for the same definition you can use the @Qualifier
stereotype to specify the implementation that you need to inject, alternatively, you can use the constructor injection to inject your bean definition as needed without auto wiring as mentioned here Spring @Autowire on Properties vs Constructor
答案3
得分: 0
我会坚持以上的答案。然而,如果你想在你的代码中保留类的进一步实例化(或者你想保留你特定的单例实现),你可以使用 getInstance()
方法来实现。
首先,在你的类中去掉 @Component
注解:
// @Component
public class TransactionStatisticsCacheImpl implements TransactionCache {
private static TransactionStatisticsCacheImpl instance;
public static TransactionStatisticsCacheImpl getInstance(){
if(Objects.isNull(instance)){
synchronized (TransactionStatisticsCacheImpl.class) {
if(Objects.isNull(instance)){
instance = new TransactionStatisticsCacheImpl();
}
}
}
return instance;
}
private TransactionStatisticsCacheImpl() {}
}
然后,你可以通过定义 @Configuration
类来实例化你的单例 @Bean
,这样你的 Bean 将会被 Spring 容器管理:
@Configuration
public class SingletonConfiguration {
@Bean
public TransactionCache transactionCache() {
return TransactionCacheImpl.getInstance();
}
}
最后,你可以在你的 RestController 中使用 @Autowired
将你的单例注入进来:
@RestController
public class StatisticsController {
private TransactionCache transactionCache;
@Autowired
public StatisticsController(TransactionCache transactionCache) {
this.transactionCache = transactionCache;
}
@PostMapping("/tick")
public ResponseEntity<Object> addInstrumentTransaction(@Valid @RequestBody InstrumentTransaction instrumentTransaction) {
transactionCache.addTransaction(instrumentTransaction);
return new ResponseEntity<>(HttpStatus.CREATED);
}
}
英文:
I would stick to the answers above. However, if you want to preserve further instantiation of the class in your code (or you want to keep your specific implementation of singleton), you can do it with getInstance()
.
Firstly, get rid of @Component
annotation in your class:
// @Component
public class TransactionStatisticsCacheImpl implements TransactionCache {
private static TransactionStatisticsCacheImpl instance;
public static TransactionStatisticsCacheImpl getInstance(){
if(Objects.isNull(instance)){
synchronized (TransactionStatisticsCacheImpl.class) {
if(Objects.isNull(instance)){
instance = new TransactionStatisticsCacheImpl();
}
}
}
return instance;
}
private TransactionStatisticsCacheImpl() {}
}
Then, you may instantiate your singleton @Bean
by defining @Configuration
class - this way your bean would get managed by spring container.
@Configuration
public class SingletonConfiguration {
@Bean
public TransactionCache transactionCache() {
return TransactionCacheImpl.getInstance();
}
}
Eventually, you can have your singleton injected in your RestController using @Autowired
.
@RestController
public class StatisticsController {
private TransactionCache transactionCache;
@Autowired
public StatisticsController(TransactionCache transactionCache) {
this.transactionCache = transactionCache;
}
@PostMapping("/tick")
public ResponseEntity<Object> addInstrumentTransaction(@Valid @RequestBody InstrumentTransaction instrumentTransaction) {
transactionCache.addTransaction(instrumentTransaction);
return new ResponseEntity<>(HttpStatus.CREATED);
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论