table of Contents
- Singleton (Singleton) Scope
- Prototype (Prototype) Scope
- A plurality of parallel execution The method of HTTP requests or internal serial controller Spring?
- Example single-mode and analog large number of concurrent requests, authentication security thread
- Appendix: Spring Bean scopes
Singleton (Singleton) Scope
Each add or @RestController @Controller controller, the default is a singleton (Singleton), which is the default scope Spring Bean's.
The following code example with reference to the Building a RESTful the Web-Service A , the project-based tutorial Spring Boot web structures, the source code may refer to spring-guides / gs-rest- service
GreetingController.java code is as follows:
package com.example.controller;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
@GetMapping("/greeting")
public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
Greeting greet = new Greeting(counter.incrementAndGet(), String.format(template, name));
System.out.println("id=" + greet.getId() + ", instance=" + this);
return greet;
}
}
We use HTTP benchmarking tool wrk to generate a large number of HTTP requests. In order to test the terminal input as follows:
wrk -t12 -c400 -d10s http://127.0.0.1:8080/greeting
In the standard output of the server side, you can see similar logs.
id=162440, instance=com.example.controller.GreetingController@368b1b03
id=162439, instance=com.example.controller.GreetingController@368b1b03
id=162438, instance=com.example.controller.GreetingController@368b1b03
id=162441, instance=com.example.controller.GreetingController@368b1b03
id=162442, instance=com.example.controller.GreetingController@368b1b03
id=162443, instance=com.example.controller.GreetingController@368b1b03
id=162444, instance=com.example.controller.GreetingController@368b1b03
id=162445, instance=com.example.controller.GreetingController@368b1b03
id=162446, instance=com.example.controller.GreetingController@368b1b03
GreetingController all instances the log address are the same, indicating that multiple requests for the same example GreetingController processed and its counter AtomicLong type field is increasing at each call as expected.
Prototype (Prototype) Scope
If we add @Scope ( "prototype") notes over @RestController comment, the bean scope to become the prototype scope, the other contents remain unchanged.
...
@Scope("prototype")
@RestController
public class GreetingController {
...
}
Standard output log server is as follows, described prototype scope changed after each request creates a new the bean, thus the returned id is always 1, bean instances different addresses.
id=1, instance=com.example.controller.GreetingController@2437b9b6
id=1, instance=com.example.controller.GreetingController@c35e3b8
id=1, instance=com.example.controller.GreetingController@6ea455db
id=1, instance=com.example.controller.GreetingController@3fa9d3a4
id=1, instance=com.example.controller.GreetingController@3cb58b3
A plurality of parallel execution The method of HTTP requests or internal serial controller Spring?
If we add sleep time in greeting () method, the method to see whether each http request will invoke the serial controller inside the next.
@RestController
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
@GetMapping("/greeting")
public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) throws InterruptedException {
Thread.sleep(1000); // 休眠1s
Greeting greet = new Greeting(counter.incrementAndGet(), String.format(template, name));
System.out.println("id=" + greet.getId() + ", instance=" + this);
return greet;
}
}
Or used to create a large number wrk request, the server can be seen that even if the method of sleep one second, resulting in an average delay per request reaches 1.18s, but the request can be processed per second, still reached 166, the HTTP request proof is internally Spring MVC the method of concurrent calls controllers, rather than serially.
wrk -t12 -c400 -d10s http://127.0.0.1:8080/greeting
Running 10s test @ http://127.0.0.1:8080/greeting
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.18s 296.41ms 1.89s 85.22%
Req/Sec 37.85 38.04 153.00 80.00%
1664 requests in 10.02s, 262.17KB read
Socket errors: connect 155, read 234, write 0, timeout 0
Requests/sec: 166.08
Transfer/sec: 26.17KB
Example single-mode and analog large number of concurrent requests, authentication security thread
Singleton class definitions: Singleton.java
package com.demo.designpattern;
import java.util.concurrent.atomic.AtomicInteger;
public class Singleton {
private volatile static Singleton singleton;
private int counter = 0;
private AtomicInteger atomicInteger = new AtomicInteger(0);
private Singleton() {
}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
public int getUnsafeNext() {
return ++counter;
}
public int getUnsafeCounter() {
return counter;
}
public int getSafeNext() {
return atomicInteger.incrementAndGet();
}
public int getSafeCounter() {
return atomicInteger.get();
}
}
Test singleton class and create a large number of concurrent requests call: SingletonTest.java
package com.demo.designpattern;
import java.util.*;
import java.util.concurrent.*;
public class SingletonTest {
public static void main(String[] args) {
// 定义可返回计算结果的非线程安全的Callback实例
Callable<Integer> unsafeCallableTask = () -> Singleton.getSingleton().getUnsafeNext();
runTask(unsafeCallableTask);
// unsafe counter may less than 1000, i.e. 984
System.out.println("current counter = " + Singleton.getSingleton().getUnsafeCounter());
// 定义可返回计算结果的线程安全的Callback实例(基于AtomicInteger)
Callable<Integer> safeCallableTask = () -> Singleton.getSingleton().getSafeNext();
runTask(safeCallableTask);
// safe counter should be 1000
System.out.println("current counter = " + Singleton.getSingleton().getSafeCounter());
}
public static void runTask(Callable<Integer> callableTask) {
int cores = Runtime.getRuntime().availableProcessors();
ExecutorService threadPool = Executors.newFixedThreadPool(cores);
List<Callable<Integer>> callableTasks = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
callableTasks.add(callableTask);
}
Map<Integer, Integer> frequency = new HashMap<>();
try {
List<Future<Integer>> futures = threadPool.invokeAll(callableTasks);
for (Future<Integer> future : futures) {
frequency.put(future.get(), frequency.getOrDefault(future.get(), 0) + 1);
//System.out.printf("counter=%s\n", future.get());
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
threadPool.shutdown();
}
}
Appendix: the Spring Bean scopes
range
|
description |
---|---|
singleton (singleton) | (Default) defined range for each individual bean Spring IoC container is defined as a single object instance. In other words, when you define a single bean and scope thereof embodiment, Spring IoC container creates an instance of that object as defined bean. The singleton embodiment beans stored in a single cache, and all subsequent requests to the named references bean and return the cached object. |
prototype (prototype) | The individual bean scoped defined as any number of object instances. Each time a request for a particular bean, bean prototype scope will create a new bean instance. That is, the Bean Bean injected into another, or you can call getBean on the container () method to request it. Typically, prototype scope should be used for all stateful Bean, the scope of a single embodiment for the stateless Bean. |
request | The defined range is defined as an individual bean life of a single HTTP request. That is, each HTTP request has bean instance created after a single bean definition. Only valid in the context of web-aware Spring ApplicationContext. |
session | The range of a single bean defined HTTP Session is defined as the life cycle. Only in the context of web-based Spring ApplicationContext effective. |
application | The defined range is defined as an individual bean ServletContext lifecycle. Only in the context of web-based Spring ApplicationContext effective. |
websocket | The individual bean scoped WebSocket defined lifecycle. Only in the context of web-based Spring ApplicationContext effective. |