Кеш загрузки Spring не работает с @PostConstruct или @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

}

studentService

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");
    }

}

StudentController

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: // локальный: 8080 / студент / 1 в первый раз, кеш не активен, и ответ занимает более 5 секунд, но когда я обновляюсь, кеш отвечает, и запрос занимает несколько миллисекунд! несмотря на то, что я вызвал метод кеширования в postConstruct, я попытался использовать @AfterPropertiesSet, и он тоже не работает!

Любая идея ?

Спасибо

Название должно быть на английском языке.

shmosel 30.11.2018 09:43

Ваш метод init() действительно выполняется?

Mark 30.11.2018 09:45

Да, выполняется при запуске весны

d48b 30.11.2018 10:11
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
3
2 814
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Это не работает, потому что прокси еще не инициализирован. На самом деле это задокументировано в руководстве пользователя

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).

Это именно то, что вы здесь делаете. Кеширование должно быть максимально прозрачным, поэтому предварительная загрузка кеша при запуске кажется мне немного странной (и увеличивает время запуска).

Можете ли вы опубликовать пример конфигурации aspectj, если это возможно?

d48b 30.11.2018 10:18

если я устанавливаю метод, который я запускаю в асинхронном режиме через 1 минуту после загрузки контекстной пружины, разве это не чище, чем использование аспектаj?

d48b 30.11.2018 11:11
Ответ принят как подходящий

Ответ прост, но мне потребовалось почти день, чтобы понять, что методы, украшенные @Cacheable, не действуют в @PostConstruct.

Просто замените ваш @PostConstruct на @EventListener (ApplicationReadyEvent.class)

@EventListener(ApplicationReadyEvent.class)
public void init() {
    studentService.getStudentByID("1");
}

NB. Если исключение генерируется из метода, украшенного событием @PostConstruct или EventListener (ApplicationReadyEvent.class), ваше приложение завершит работу ...

Другие вопросы по теме