简体   繁体   English

Spring Boot 中的可缓存注解

[英]Cacheable Annotation in Spring Boot

Service Class服务等级

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
public class StudentService{
   
    @Cacheable(value = "student",key = "{#id,#name}")
    public Student getStudentByID(String id,String name)
    {
        return new Student(id,name ,"V");
    }
} 

ThreadExample Class线程示例类

 public class ThreadExample extends   Thread{

    @Autowired
    StudentService studentService;

    @Override
    public void run() {
        studentService.getStudentByID("3","f");
    }
}

I have both class and start the threads as :我有两个类并将线程启动为:


  for (int i = 0; i < 24; i++) {
      new ThreadExample().start();
  }

The problem is cacheable annotation does not work here , because it is not a spring bean class.问题是可缓存注解在这里不起作用,因为它不是 Spring bean 类。 But the things I try to do just execute one time getStudentByID(String id,String name) function with same id and name.但是我尝试做的事情只是执行一次具有相同 ID 和名称的getStudentByID(String id,String name)函数。 How I can do that ?我怎么能做到这一点? Do you have any idea.你有什么主意吗。 Thank you谢谢

StudentService in ThreadExample class would be null because; ThreadExample类中的StudentService将为null ,因为;

Spring only autowires components the components it creates. Spring仅自动装配它创建的组件。 You are calling new ThreadExample() , Spring doesn't know about this object so no auto-wiring will take place.您正在调用new ThreadExample()Spring不知道该对象,因此不会发生自动装配。 See https://stackoverflow.com/a/42502608/2039546https://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.第一个也是最快的选择是使用构造函数将服务发送到ThreadExample类。 You can do this easily.你可以很容易地做到这一点。

  • Other option when you create ThreadExample ask app context to do your auto-wiring.创建ThreadExample时的其他选项要求应用程序上下文进行自动连接。 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.注意sync = true属性,它告诉框架在计算值时阻塞任何并发线程。 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]
.
.
.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM