英文:
SpringBoot cache not working for non parameter methods
问题
我有一个Spring Boot应用程序
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>cachedemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>cachedemo</name>
<description>Demo project for Spring Boot cache</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<!-- <version>2.2.6.RELEASE</version> -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
CacheDemoAllpication.java
package com.example.cachedemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class CachedemoApplication {
public static void main(String[] args) {
SpringApplication.run(CachedemoApplication.class, args);
}
}
Controller
package com.example.cachedemo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.example.cachedemo.model.Book;
import com.example.cachedemo.service.LibraryService;
@Controller
public class HomeController {
@Autowired
private LibraryService service;
@RequestMapping("/get")
public String getBooks(@RequestParam Integer id) {
Book book = service.getBook(id);
System.out.println(book);
return book.toString();
}
}
Service
package com.example.cachedemo.service;
import java.util.HashMap;
import java.util.Map;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import com.example.cachedemo.model.Book;
@Service
public class LibraryService {
// @Cacheable(value = "bookCache")
public Book getBook(Integer id) {
System.out.println("*******************************************Method called getBook()************************************");
Map<Integer, Book> bookMap = getBookMap();
return bookMap.get(id);
}
@Cacheable(value = "booksCache", key="#root.methodName")
private Map<Integer, Book> getBookMap()
{
Book b3 = new Book(2, "Peace", "Arif");
Book b2 = new Book(3, "Mumbai City", "Shiv Shankar");
Book b1 = new Book(1, "Test", "Sunny");
Map<Integer, Book> bookMap = new HashMap<Integer, Book>();
bookMap.put(1, b1);
bookMap.put(2, b2);
bookMap.put(3, b3);
System.out.println("*******************************************Method called getBookMap()************************************");
return bookMap;
}
}
在服务类中的 **getBookMap()** 方法返回一个 Map,我希望 Spring 将其缓存。对于后续的请求,它应该从缓存中返回该 Map。但是在当前的设置下,它没有缓存任何内容,**getBookMap()** 方法每次都被执行。
我最初怀疑是 **spring-boot-starter-cache** 版本的问题,但事实并非如此。最新版本的行为也是一样的。
我尝试过使用/不使用 **key="#root.methodName"**,但结果是一样的。
然而,如果我缓存 **getBook(Integer id)** 方法,它就可以正常工作,这让我觉得无参数的方法行为不同。
英文:
I have one spring boot application
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>cachedemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>cachedemo</name>
<description>Demo project for Spring Boot cache</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<!-- <version>2.2.6.RELEASE</version> -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
CacheDemoAllpication.java
package com.example.cachedemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class CachedemoApplication {
public static void main(String[] args) {
SpringApplication.run(CachedemoApplication.class, args);
}
}
Controller
package com.example.cachedemo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.example.cachedemo.model.Book;
import com.example.cachedemo.service.LibraryService;
@Controller
public class HomeController {
@Autowired
private LibraryService service;
@RequestMapping("/get")
public String getBooks(@RequestParam Integer id) {
Book book = service.getBook(id);
System.out.println(book);
return book.toString();
}
}
Service
package com.example.cachedemo.service;
import java.util.HashMap;
import java.util.Map;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import com.example.cachedemo.model.Book;
@Service
public class LibraryService {
// @Cacheable(value = "bookCache")
public Book getBook(Integer id) {
System.out.println("*******************************************Method called getBook()************************************");
Map<Integer,Book> bookMap = getBookMap();
return bookMap.get(id);
}
@Cacheable(value = "booksCache", key="#root.methodName")
private Map<Integer,Book> getBookMap()
{
Book b3 = new Book(2,"Peace","Arif");
Book b2 = new Book(3,"Mumbai City","Shiv Shankar");
Book b1 = new Book(1,"Test","Sunny");
Map<Integer,Book> bookMap = new HashMap<Integer, Book>();
bookMap.put(1, b1);
bookMap.put(2, b2);
bookMap.put(3, b3);
System.out.println("*******************************************Method called getBookMap()************************************");
return bookMap;
}
}
In the service class getBookMap() return a Map and I want spring to cache that. For subsequent requests it should return that map from cache. But with current setup It's not caching anything and getBookMap() method is being executed every time.
My first suspect was spring-boot-starter-cache version, but that's not the case. The behavior is same with latest version as well.
I have tried with/without key="#root.methodName" but the result is same.
Whereas if I cache method getBook(Integer id) it works just fine which gets me into thinking that no parameter methods are behaving differently.
答案1
得分: 4
Sure, here's the translation:
@Cacheable
在私有方法上不起作用,请将您的方法改为公共方法。- 您无法从同一类中调用带有缓存的方法。我是说将您的
@Cacheable
方法放入另一个类中并将其设为公共方法。从另一个类中调用该方法。然后它就会起作用。
英文:
- @Cacheable won't work for private methods, make your method public
- You can't call a cacheable method from within the same class. I mean put your Cacheable method into another class and make it public. Call the method from another class. Then it'll work
答案2
得分: 2
Spring使用Spring AOP来实现声明式缓存(使用代理)。
通过在getBook
方法上加上@Cacheable
注解并且从外部调用,由于调用经过代理,所以能够正常工作。
在你的LibraryService
类内部调用getBookMap
方法的话,该方法不会经过代理,也不会被通知,这意味着缓存不会被触发。要么将该方法提取到另一个类中并从LibraryService
中调用它,要么使用AspectJ
。
进一步阅读:Spring AOP
英文:
Spring uses Spring AOP to implement declarative caching (using proxies).
Annotating the getBook
method with @Cacheable
and calling it from the outside works as the call goes through the proxy.
You are calling getBookMap
internally in your LibraryService
class, that method won't go through the proxy and won't be advised , which means caching won't be triggered. Either extract the method to another class and call it from your LibraryService
or use AspectJ
.
Further reading: Spring AOP
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论