CodeMaster
CodeMaster

Reputation: 171

Call singleton class in spring boot rest api controller

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?

Upvotes: 0

Views: 2135

Answers (3)

mareck_ste
mareck_ste

Reputation: 517

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);
    }
}

Upvotes: 0

MaxExplode
MaxExplode

Reputation: 2007

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

Upvotes: 0

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.

Upvotes: 4

Related Questions