调用 Spring Boot REST API 控制器中的单例类

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

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(&quot;/tick&quot;)
    public ResponseEntity&lt;Object&gt; addInstrumentTransaction(@Valid @RequestBody InstrumentTransaction instrumentTransaction) {
        transactionCache.addTransaction(instrumentTransaction);
        return new ResponseEntity&lt;&gt;(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(&quot;/tick&quot;)
    public ResponseEntity&lt;Object&gt; addInstrumentTransaction(@Valid @RequestBody InstrumentTransaction instrumentTransaction) {
        transactionCache.addTransaction(instrumentTransaction);
        return new ResponseEntity&lt;&gt;(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(&quot;/tick&quot;)
    public ResponseEntity&lt;Object&gt; addInstrumentTransaction(@Valid @RequestBody InstrumentTransaction instrumentTransaction) {
        transactionCache.addTransaction(instrumentTransaction);
        return new ResponseEntity&lt;&gt;(HttpStatus.CREATED);
    }
}

huangapple
  • 本文由 发表于 2020年9月22日 13:31:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/64003588.html
匿名

发表评论

匿名网友

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

确定