SpringBoot缓存在不带参数的方法中不起作用

huangapple go评论78阅读模式
英文:

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

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
&lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
&lt;parent&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;
&lt;version&gt;2.3.4.RELEASE&lt;/version&gt;
&lt;relativePath/&gt; &lt;!-- lookup parent from repository --&gt;
&lt;/parent&gt;
&lt;groupId&gt;com.example&lt;/groupId&gt;
&lt;artifactId&gt;cachedemo&lt;/artifactId&gt;
&lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;
&lt;name&gt;cachedemo&lt;/name&gt;
&lt;description&gt;Demo project for Spring Boot cache&lt;/description&gt;
&lt;properties&gt;
&lt;java.version&gt;1.8&lt;/java.version&gt;
&lt;/properties&gt;
&lt;dependencies&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-cache&lt;/artifactId&gt;
&lt;!-- &lt;version&gt;2.2.6.RELEASE&lt;/version&gt; --&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
&lt;scope&gt;test&lt;/scope&gt;
&lt;exclusions&gt;
&lt;exclusion&gt;
&lt;groupId&gt;org.junit.vintage&lt;/groupId&gt;
&lt;artifactId&gt;junit-vintage-engine&lt;/artifactId&gt;
&lt;/exclusion&gt;
&lt;/exclusions&gt;
&lt;/dependency&gt;
&lt;/dependencies&gt;
&lt;build&gt;
&lt;plugins&gt;
&lt;plugin&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
&lt;/plugin&gt;
&lt;/plugins&gt;
&lt;/build&gt;
&lt;/project&gt;

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(&quot;/get&quot;)
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 = &quot;bookCache&quot;)
public Book getBook(Integer id) {
System.out.println(&quot;*******************************************Method called getBook()************************************&quot;);
Map&lt;Integer,Book&gt; bookMap = getBookMap();
return bookMap.get(id);
}
@Cacheable(value = &quot;booksCache&quot;, key=&quot;#root.methodName&quot;)
private Map&lt;Integer,Book&gt; getBookMap()
{
Book b3 = new Book(2,&quot;Peace&quot;,&quot;Arif&quot;);
Book b2 = new Book(3,&quot;Mumbai City&quot;,&quot;Shiv Shankar&quot;);
Book b1 = new Book(1,&quot;Test&quot;,&quot;Sunny&quot;);
Map&lt;Integer,Book&gt; bookMap = new HashMap&lt;Integer, Book&gt;();
bookMap.put(1, b1);
bookMap.put(2, b2);
bookMap.put(3, b3);
System.out.println(&quot;*******************************************Method called getBookMap()************************************&quot;);
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:

  1. @Cacheable 在私有方法上不起作用,请将您的方法改为公共方法。
  2. 您无法从同一类中调用带有缓存的方法。我是说将您的 @Cacheable 方法放入另一个类中并将其设为公共方法。从另一个类中调用该方法。然后它就会起作用。
英文:
  1. @Cacheable won't work for private methods, make your method public
  2. 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

huangapple
  • 本文由 发表于 2020年10月11日 19:47:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/64303645.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定