2015-01-14 3 views
9

Я использую пружинный кэш для улучшения запросов к базе данных, которая прекрасно работает следующим образом:Как загрузить @Cache при запуске весной?

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

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

Но теперь я хочу, чтобы предварительно заполнить всю книгу-кэш при запуске. Это означает, что я хочу позвонить dao.findAll() и поместить все значения в кеш. Эта процедура должна планироваться только периодически.

Но как я могу заполнить кеш при использовании @Cacheable?

ответ

7

Просто используйте кеш, как и прежде, добавьте планировщик для обновления кеша, снимок кода ниже.

@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 возвращает объект для одного параметра (по умолчанию). Или еще, выведите метод putToCache в BookService, чтобы избежать непосредственного использования cacheManager.

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

Если у вас есть все экземпляры книги в памяти при запуске, это ваше требование, чем вы должны хранить их в каком-то буфере самостоятельно. Ввод их в кэш с помощью метода findAll() означает, что вы должны аннотировать findAll() с помощью @Cacheable. Затем вам придется вызвать findAll() при запуске. Но это не значит, что вызов getByIsbn (String isbn) будет обращаться к кешу, даже если соответствующий экземпляр был помещен в кеш при вызове findAll(). На самом деле это не потому, что ehcache будет кэшировать возвращаемое значение метода как пару ключ/значение, где ключ вычисляется при вызове метода. Поэтому я не вижу, как вы могли бы сопоставить возвращаемое значение findAll() и возвращаемое значение getByIsbn (String), потому что возвращаемые типы не совпадают, и, кроме того, ключ не будет соответствовать всем вашим экземплярам.

0

Добавить другой боб BookCacheInitialzer

Autowire текущий боб BookService в BookCacheInitialzer

в методе PostConstruct из BookCacheInitialzer псевдокоде

Тогда можно сделать что-то вроде

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

} 

}

+0

Да, это был бы вариант, но очень плохой для производительности, поскольку я нажимаю DB n-times во время запуска для каждой записи. И более того, это как-то избыточно, поскольку у меня уже есть все мои книги с помощью 'findAll()'. Таким образом, я ищу способ получить эти книги в кеш без другого обратного перехода к db. – membersound

+0

Тогда можно сделать что-то вроде –

+0

Отредактировано солном соответственно. –

1

Как Оливье указал, так как весной кэшей вывода функции как единого объекта, используя @cacheable обозначения с FindAll не позволит загрузить все объекты в кэше таким образом, чтобы они в дальнейшем могут быть доступны по отдельности ,

Одним из возможных способов загрузки всех объектов в кеш является использование кэширующего решения, позволяющее загружать все объекты при запуске. Например, такие решения, как NCache/TayzGrid, обеспечивают загрузчик загрузки кэша, который позволяет загружать кеш при запуске с помощью объектов с помощью настраиваемого загрузчика загрузки кеша.

2

Возможна установка CommandLineRunner для заполнения кеша при запуске.

Из официальной документации CommandLineRunner, это:

Интерфейс, используемый для указания того, что боб должен запустить, если оно содержится в SpringApplication.

Следовательно, нам просто нужно получить список всех доступных книг, а затем, используя 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)); 
    } 
} 
Смежные вопросы