The server dispatches an idle thread from the thread pool to handle each request it receives. In spring’s integrated Web, controllers and services are typically singletons, which results in whether your Example is singletons or multiple instances. There is only one Example for the same service. The following problems occur when multithreading accesses the service

Details on the problem

The project directory structure is as follows

The service () method of MyService takes two parameters and queries the database accordingly

@Service public class MyService { @Autowired StudentMapper studentMapper; @Autowired StudentExample studentExample; public void service(Integer begin,Integer end){ StudentExample.Criteria criteria1 = studentExample.createCriteria(); criteria1.andAgeBetween(begin,end); List<Student> list=studentMapper.selectByExample(studentExample); studentExample.clear(); System.out.println(list); }}Copy the code

If two requests exist at the same time, the StudentExample of the two requests is the same

Request 1 begin=2,end=8

Request 2 begins =4,end=8

Request 1 is allowed and the condition is added successfully

Request 2 is allowed. Request 2 fails to be added

If studentexample.clear () is executed in request 2 before request 1, the query conditions in request 1 are invalid

Neither request has the correct result at this point.

The solution

We can use ThreadLocal to assign a separate Example to each thread. To ensure that we get a value each time, we simply extend ThreadLocal. If the current thread does not have an Example, we get one from the Spring container and bind it to the thread.

ThreadLocalExtension

Public class ThreadLocalExtension<T> extends ThreadLocal<T> {// Get the ApplicationContext method from @autoWired ApplicationContext applicationContext; publicThreadLocalExtension(){
        super();
    }
    public T get(Class<T> example){
        T bean=super.get();
        if(bean==null){
            super.set((T) applicationContext.getBean(example));
        }
        returnsuper.get(); }}Copy the code

Spring generic dependency injection

Since there are many examples, generics are used here, and spring4.0 provides support for generic dependency injection. First, the ThreadLocalExtension corresponding to the actual type is managed by spring

@Repository
public class StudentExampleThreadLocal extends ThreadLocalExtension<StudentExample> {
}
Copy the code

It is then injected directly into the code

@Autowired
ThreadLocalExtension<StudentExample> studentExampleThreadLocal;
Copy the code

Modified MyService

@Service public class MyService { @Autowired StudentMapper studentMapper; @Autowired ThreadLocalExtension<StudentExample> studentExampleThreadLocal; public void service(Integer begin,Integer end){ StudentExample studentExample = studentExampleThreadLocal.get(StudentExample.class); StudentExample.Criteria criteria1 = studentExample.createCriteria(); criteria1.andAgeBetween(begin,end); List<Student> list=studentMapper.selectByExample(studentExample); studentExample.clear(); System.out.println(list); }}Copy the code

Get ApplicationContext

Create a class that implements ApplicationContextAware and injects applicationContext into the Spring container

@Component
public class ApplicationContextHelper implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    public ApplicationContextHelper() {
    }
    @Bean(name="applicationContext")
    public ApplicationContext getApplicationContext() {return applicationContext;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationContextHelper.applicationContext = applicationContext;
    }

    public static Object getBean(String beanName) {
        returnapplicationContext ! = null? applicationContext.getBean(beanName):null; }}Copy the code

The results of

Now that the transformation is complete, look at the effect request 1

Request 2

Each request obtains a different StudentExample, so there is no conflict. StudentExample does not create or destroy a large number of threads, but only creates the same number of threads in the server thread pool, so it can be reused