Tom Shir
Tom Shir

Reputation: 482

Static variable in the scope of a Java rest service

I have an APIController class defined with a @RestController annotation, which holds several REST services, defined with the @RequestMapping annotation.

I'm looking for a way to define a "static" integer which will be initialized to 0 on every REST call.

My goal is to define a singleton with a scope of a REST instance / call, and not with the scope of the entire application.

For example: I have a getData REST, which calls the internal function getSingletonData twice. First call to getSingletonData will return 1 and the second will return 2.

Once another user will call the getData rest service, the same function getSingletonData will return again 1 and 2, and not 3 and 4 (which will happen in case the internal integer variable will be defined as static?).

I know I can just define the variable as a local variable inside the REST service, but I want to avoid passing it as a parameter to many functions, and I would like the class to be a singleton (the class just returns sequential numbers whenever asked, in the scope of that specific REST call).

Upvotes: 2

Views: 2388

Answers (1)

Edwin Dalorzo
Edwin Dalorzo

Reputation: 78589

Well, one way to solve your problem is by defining a request-based bean. You see, Spring components may have different scopes: e.g. singleton, prototype, request, and session.

So, you could define a bean whose scope is the "request" itself. By doing this you'd get a fresh instance of it injected per request in e.g. your controller.

You could define such a data provider somewhat as follows:

@Configuration
public class DataProviderConfiguration {

    @Bean
    @Scope(scopeName = WebApplicationContext.SCOPE_REQUEST,
            proxyMode = ScopedProxyMode.INTERFACES)
    public Supplier<Integer> getRequestDataProvider() {
        AtomicInteger value = new AtomicInteger();
        return value::incrementAndGet;
    }

}

And then in your controller, you would get an instance of it injected per request using classical injection.

@RestController
public class DataProviderController {

    @Autowired
    private Supplier<Integer> requestDataProvider;

    @GetMapping("/answers")
    public Integer[] getAnswer() {
        return new Integer[]{requestDataProvider.get(), requestDataProvider.get()};
    }

}

And this will consistently produce the result [1,2] per every request, which seems to be what you wanted to achieve.

Upvotes: 3

Related Questions