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