복붙노트

[SPRING] 봄에 시작할 때 @Cache를로드하는 방법?

SPRING

봄에 시작할 때 @Cache를로드하는 방법?

나는 봄 캐시를 사용하여 다음과 같이 잘 작동하는 데이터베이스 쿼리를 향상시키고있다.

@Bean
public CacheManager cacheManager() {
    return new ConcurrentMapCacheManager("books");
}

@Cacheable("books")
public Book getByIsbn(String isbn) {
    return dao.findByIsbn(isbn);
}

하지만 이제 시작할 때 전체 책 캐시를 미리 채워 넣고 싶습니다. 즉, dao.findAll ()을 호출하고 모든 값을 캐시에 저장하려고합니다. 이 루틴은 주기적으로 만 예약되어야합니다.

하지만 @Cacheable을 사용할 때 명시 적으로 캐시를 채울 수 있습니까?

해결법

  1. ==============================

    1.이전과 같이 캐시를 사용하고, 캐시를 업데이트하는 스케줄러를 추가하고, 코드 스 니펫은 아래에 있습니다.

    이전과 같이 캐시를 사용하고, 캐시를 업데이트하는 스케줄러를 추가하고, 코드 스 니펫은 아래에 있습니다.

    @Service
    public class CacheScheduler {
        @Autowired
        BookDao bookDao;
        @Autowired
        CacheManager cacheManager;
    
        @PostConstruct
        public void init() {
            update();
            scheduleUpdateAsync();
        }
    
        public void update() {
            for (Book book : bookDao.findAll()) {
                cacheManager.getCache("books").put(book.getIsbn(), book);
            }
        }
    }
    

    KeyGenerator가 (디폴트로) 하나의 매개 변수에 대한 오브젝트를 리턴하는지 확인하십시오. 그렇지 않으면 cacheManager를 직접 사용하지 않도록 BookService의 putToCache 메소드를 노출하십시오.

    @CachePut(value = "books", key = "#book.isbn")
    public Book putToCache(Book book) {
        return book;
    }
    
  2. ==============================

    2.시작할 때 메모리의 모든 인스턴스가 필요하다면 직접 버퍼에 저장해야합니다. findAll () 메소드를 사용하여 캐시에 넣으면 findAll ()에 @Cacheable 주석을 추가해야합니다. 그런 다음 시작할 때 findAll ()을 호출해야합니다. 그러나 findAll ()을 호출 할 때 해당 인스턴스가 캐시에 저장되어 있어도 getByIsbn (String isbn)을 호출하면 캐시에 액세스한다는 것을 의미하지는 않습니다. 실제로는 ehcache가 메서드 반환 값을 메서드가 호출 될 때 key가 계산되는 키 / 값 쌍으로 캐시하기 때문에 그렇지 않습니다. 따라서 반환 된 유형이 동일하지 않으며 키가 모든 인스턴스에 대해 절대 일치하지 않으므로 findAll ()의 반환 값과 getByIsbn (String)의 반환 값을 일치시키는 방법을 알 수 없습니다.

    시작할 때 메모리의 모든 인스턴스가 필요하다면 직접 버퍼에 저장해야합니다. findAll () 메소드를 사용하여 캐시에 넣으면 findAll ()에 @Cacheable 주석을 추가해야합니다. 그런 다음 시작할 때 findAll ()을 호출해야합니다. 그러나 findAll ()을 호출 할 때 해당 인스턴스가 캐시에 저장되어 있어도 getByIsbn (String isbn)을 호출하면 캐시에 액세스한다는 것을 의미하지는 않습니다. 실제로는 ehcache가 메서드 반환 값을 메서드가 호출 될 때 key가 계산되는 키 / 값 쌍으로 캐시하기 때문에 그렇지 않습니다. 따라서 반환 된 유형이 동일하지 않으며 키가 모든 인스턴스에 대해 절대 일치하지 않으므로 findAll ()의 반환 값과 getByIsbn (String)의 반환 값을 일치시키는 방법을 알 수 없습니다.

  3. ==============================

    3.옵션은 CommandLineRunner를 사용하여 시작할 때 캐시를 채우는 것입니다.

    옵션은 CommandLineRunner를 사용하여 시작할 때 캐시를 채우는 것입니다.

    공식 CommandLineRunner 문서에서 볼 수있는 것은 다음과 같습니다.

    따라서 사용 가능한 모든 책 목록을 검색 한 다음 CacheManager를 사용하여 책 캐시를 채 웁니다.

    @Component
    public class ApplicationRunner implements CommandLineRunner {
        @Autowired
        private BookDao dao;
    
        @Autowired
        private CacheManager cacheManager;
    
        @Bean
        public CacheManager cacheManager() {
            return new ConcurrentMapCacheManager("books");
        }
    
        @Override
        public void run(String... args) throws Exception {
    
            List<Book> results = dao.findAll();
    
            results.forEach(book -> 
                cacheManager.getCache("books").put(book.getId(), book));
        }
    }
    
  4. ==============================

    4.올리비에 (Olivier)가 지정했듯이, 스프링 캐시가 단일 객체로 함수를 출력하기 때문에 findAll로 @cacheable 표기법을 사용하면 나중에 개별적으로 액세스 할 수 있도록 캐시의 모든 객체를로드 할 수 없습니다.

    올리비에 (Olivier)가 지정했듯이, 스프링 캐시가 단일 객체로 함수를 출력하기 때문에 findAll로 @cacheable 표기법을 사용하면 나중에 개별적으로 액세스 할 수 있도록 캐시의 모든 객체를로드 할 수 없습니다.

    캐시에있는 모든 오브젝트를로드 할 수있는 한 가지 방법은 사용중인 캐시 솔루션이 시작시 모든 오브젝트를로드하는 방법을 제공하는지 여부입니다. 예를 들어 NCache / TayzGrid와 같은 솔루션은 구성 가능한 캐시 시작 로더를 사용하여 개체를 시작할 때 캐시를로드 할 수있는 캐시 시작 로더 기능을 제공합니다.

  5. ==============================

    5.@PostConstruct를 사용할 때 다음과 같은 문제가 발생했습니다. - 비록 캐시 된 메서드를 호출했지만 swagger에서 호출 한 후에도 여전히 캐시 된 값을 사용하지 않았습니다. 한 번 더 전화 한 후에.

    @PostConstruct를 사용할 때 다음과 같은 문제가 발생했습니다. - 비록 캐시 된 메서드를 호출했지만 swagger에서 호출 한 후에도 여전히 캐시 된 값을 사용하지 않았습니다. 한 번 더 전화 한 후에.

    왜냐하면 @PostConstruct가 너무 빨라서 뭔가를 캐싱하기 때문입니다. (적어도 나는 그것이 문제라고 생각한다)

    이제는 시동 과정에서 더 늦게 사용하고 있으며 문제없이 작동합니다.

    @Component
    public class CacheInit implements ApplicationListener<ApplicationReadyEvent> {
    
        @Override
        public void onApplicationEvent(ApplicationReadyEvent event) {
           //call service method
        }
    
    }
    
  6. ==============================

    6.다른 빈 BookCacheInitialzer를 추가하십시오.

    다른 빈 BookCacheInitialzer를 추가하십시오.

    BookCacheInitialzer에서 현재 Bean BookService를 자동 와이어 링합니다.

    BookCacheInitialzer의 PostConstruct 메소드에서 의사 코드

    다음과 같이 할 수 있습니다.

    class BookService {
       @Cacheable("books")
       public Book getByIsbn(String isbn) {
            return dao.findByIsbn(isbn);
       }
    
        public List<Book> books;
    
        @Cacheable("books")
        public Book getByIsbnFromExistngBooks(String isbn) {
            return searchBook(isbn, books);
        }
    

    }

     class BookCacheInitialzer {
    
    @Autowired
    BookService  service
    
    @PostConstruct
    public void initialize() {
            books = dao.findAll();
        service.books = books;
        for(Book book:books) {
            service.getByIsbnFromExistngBooks(book.getIsbn());
        }
    
    }   
    

    }

  7. from https://stackoverflow.com/questions/27940704/how-to-load-cache-on-startup-in-spring by cc-by-sa and MIT license