Spring Controller cases and security threads that thing alone

table of Contents


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.

Guess you like

Origin www.cnblogs.com/sxpujs/p/12586743.html