Spring 引导缓存无法与@PostConstruct 或@AfterPropertiesSet 一起使用
Spring boot cache not working with @PostConstruct or @AfterPropertiesSet
我尝试在我的应用程序启动时用数据初始化我的缓存,但它不起作用。
我的代码:
springBootApplication
package com.r2b.springcache;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan("com.r2b")
@SpringBootApplication
@EnableCaching
public class SpringCacheApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCacheApplication.class, args);
}
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("student");
}
}
学生
package com.r2b.model;
public class Student {
String id;
String name;
String clz;
public Student(String id, String name, String clz) {
super();
this.id = id;
this.name = name;
this.clz = clz;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClz() {
return clz;
}
public void setClz(String clz) {
this.clz = clz;
}
//Setters and getters
}
学生服务
package com.r2b.service;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import com.r2b.model.Student;
@Service
public class StudentService
{
@Cacheable("student")
public Student getStudentByID(String id)
{
try
{
System.out.println("Going to sleep for 5 Secs.. to simulate backend call.");
Thread.sleep(1000*5);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
return new Student(id,"Sajal" ,"V");
}
}
学生控制器
package com.r2b.controller;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import com.r2b.model.Student;
import com.r2b.service.StudentService;
@RestController
public class StudentController
{
@Autowired
StudentService studentService;
@PostConstruct
public void init() {
studentService.getStudentByID("1");
}
@GetMapping("/student/{id}")
public Student findStudentById(@PathVariable String id)
{
System.out.println("Searching by ID : " + id);
return studentService.getStudentByID(id);
}
}
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.r2b</groupId>
<artifactId>spring-cache</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-cache</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<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-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
我第一次去http://localhost:8080/student/1的时候,缓存没有激活,响应需要5秒多,但是刷新的时候,缓存有响应,请求需要几毫秒!尽管我在 postConstruct 中调用了缓存方法,但我尝试使用 @AfterPropertiesSet 但它也不起作用!
有什么想法吗?
谢谢
这不起作用,因为代理尚未初始化。这实际上是 documented in the user guide
In proxy mode (the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation (in effect, a method within the target object that calls another method of the target object) does not lead to actual caching at runtime even if the invoked method is marked with @Cacheable. Consider using the aspectj mode in this case. Also, the proxy must be fully initialized to provide the expected behavior, so you should not rely on this feature in your initialization code (that is, @PostConstruct).
这正是您在这里所做的。缓存应该尽可能透明,所以在启动时预加载缓存对我来说有点奇怪(并增加启动时间)。
答案很简单,但我花了将近一天才弄清楚用@Cacheable have no effect in a @PostConstruct[=修饰的方法14=]
只需替换你的@PostConstruct with a @EventListener(ApplicationReadyEvent.class)
@EventListener(ApplicationReadyEvent.class)
public void init() {
studentService.getStudentByID("1");
}
注意如果用 @PostConstruct or EventListener(ApplicationReadyEvent.class) 事件修饰的方法抛出异常,您的应用程序将退出...
我尝试在我的应用程序启动时用数据初始化我的缓存,但它不起作用。 我的代码:
springBootApplication
package com.r2b.springcache;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan("com.r2b")
@SpringBootApplication
@EnableCaching
public class SpringCacheApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCacheApplication.class, args);
}
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("student");
}
}
学生
package com.r2b.model;
public class Student {
String id;
String name;
String clz;
public Student(String id, String name, String clz) {
super();
this.id = id;
this.name = name;
this.clz = clz;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClz() {
return clz;
}
public void setClz(String clz) {
this.clz = clz;
}
//Setters and getters
}
学生服务
package com.r2b.service;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import com.r2b.model.Student;
@Service
public class StudentService
{
@Cacheable("student")
public Student getStudentByID(String id)
{
try
{
System.out.println("Going to sleep for 5 Secs.. to simulate backend call.");
Thread.sleep(1000*5);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
return new Student(id,"Sajal" ,"V");
}
}
学生控制器
package com.r2b.controller;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import com.r2b.model.Student;
import com.r2b.service.StudentService;
@RestController
public class StudentController
{
@Autowired
StudentService studentService;
@PostConstruct
public void init() {
studentService.getStudentByID("1");
}
@GetMapping("/student/{id}")
public Student findStudentById(@PathVariable String id)
{
System.out.println("Searching by ID : " + id);
return studentService.getStudentByID(id);
}
}
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.r2b</groupId>
<artifactId>spring-cache</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-cache</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<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-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
我第一次去http://localhost:8080/student/1的时候,缓存没有激活,响应需要5秒多,但是刷新的时候,缓存有响应,请求需要几毫秒!尽管我在 postConstruct 中调用了缓存方法,但我尝试使用 @AfterPropertiesSet 但它也不起作用!
有什么想法吗?
谢谢
这不起作用,因为代理尚未初始化。这实际上是 documented in the user guide
In proxy mode (the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation (in effect, a method within the target object that calls another method of the target object) does not lead to actual caching at runtime even if the invoked method is marked with @Cacheable. Consider using the aspectj mode in this case. Also, the proxy must be fully initialized to provide the expected behavior, so you should not rely on this feature in your initialization code (that is, @PostConstruct).
这正是您在这里所做的。缓存应该尽可能透明,所以在启动时预加载缓存对我来说有点奇怪(并增加启动时间)。
答案很简单,但我花了将近一天才弄清楚用@Cacheable have no effect in a @PostConstruct[=修饰的方法14=]
只需替换你的@PostConstruct with a @EventListener(ApplicationReadyEvent.class)
@EventListener(ApplicationReadyEvent.class)
public void init() {
studentService.getStudentByID("1");
}
注意如果用 @PostConstruct or EventListener(ApplicationReadyEvent.class) 事件修饰的方法抛出异常,您的应用程序将退出...