StudentService
in ThreadExample
class would be null
because;
Spring only autowires components the components it creates. You are
calling new ThreadExample()
, Spring doesn't know about this object so no
auto-wiring will take place. See https://stackoverflow.com/a/42502608/2039546
There may be 2 different methods for this, depending on your use case;
The first and fastest option is to send the service to the ThreadExample
class with the constructor. You can do this easily.
Other option when you create ThreadExample
ask app context to do your auto-wiring. Let me give an example of this.
The pseudocode will be something like this;
@Controller
public class TestController {
private final ApplicationContext applicationContext;
public TestController(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@GetMapping(value = "/test")
public void test() {
ThreadExample threadExample = new ThreadExample();
applicationContext.getAutowireCapableBeanFactory()
.autowireBean(threadExample);
for (int i = 0; i < 24; i++) {
Thread thread = new Thread(threadExample);
thread.start();
}
}
}
public class ThreadExample implements Runnable {
@Autowired
private StudentService studentService;
@Override
public void run() {
long threadId = Thread.currentThread().getId();
String threadName = Thread.currentThread().getName();
System.out.println(String
.format("Thread has been called! [threadId=%s, threadName=%s]",
threadId, threadName));
Student student = studentService.getStudentByID("3", "f");
System.out.println(String
.format("Thread has been completed. [threadId=%s, threadName=%s, studentId=%s]",
threadId, threadName, student.getId()));
}
}
@Service
public class StudentService {
@Cacheable(value = "students", key = "{#id, #name}", sync = true)
public Student getStudentByID(String id, String name) {
System.out.println(String
.format("getStudentById() has been called! [id=%s, name=%s]", id, name));
return new Student(id, name , "V");
}
}
Notice the sync = true
attribute which tells the framework to block any concurrent threads while the value is being computed. This will make sure that this intensive operation is invoked only once in case of concurrent access.
The console output is:
Thread has been called! [threadId=40, threadName=Thread-7]
Thread has been called! [threadId=41, threadName=Thread-8]
Thread has been called! [threadId=42, threadName=Thread-9]
Thread has been called! [threadId=43, threadName=Thread-10]
.
.
.
getStudentById() has been called! [id=3, name=f] <- ONLY WORKED ONCE!
Thread has been completed. [threadId=54, threadName=Thread-21, studentId=3]
Thread has been completed. [threadId=55, threadName=Thread-22, studentId=3]
Thread has been completed. [threadId=57, threadName=Thread-24, studentId=3]
Thread has been completed. [threadId=47, threadName=Thread-14, studentId=3]
Thread has been completed. [threadId=42, threadName=Thread-9, studentId=3]
.
.
.