이 가이드는 Spring 관리 빈에서 캐싱을 활성화하는 과정을 안내합니다.
간단한 책 저장소에서 캐싱을 활성화하는 애플리케이션을 구축합니다.
먼저 책에 대한 간단한 모델을 만들어야 합니다. 다음 목록(src/main/java/guides/caching/Book.java)은 이를 수행하는 방법을 보여줍니다.
package guides.caching;
public interface BookRepository {
Book getByIsbn(String isbn);
}
{SpringData}[Spring Data]
를 사용하여 광범위한 SQL 또는 NoSQL 저장소에 대한 리포지토리 구현을 제공할 수 있었습니다. 그러나 이 가이드에서는 일부 대기 시간(네트워크 서비스, 느린 지연 또는 기타 문제)을 시뮬레이션하는 단순한 구현을 사용합니다. 다음 목록(src/main/java/guides/caching/SimpleBookRepository.java)은 이러한 저장소를 보여줍니다.
package guides.caching;
import org.springframework.stereotype.Component;
@Component
public class SimpleBookRepository implements BookRepository {
@Override
public Book getByIsbn(String isbn) {
simulateSlowService();
return new Book(isbn, "Some book");
}
// Don't do this at home
private void simulateSlowService() {
try {
long time = 3000L;
Thread.sleep(time);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
}
simulateSlowService
는 각 getByIsbn
호출에 의도적으로 3초 지연을 삽입합니다. 나중에 캐싱을 사용하여 이 예제의 속도를 높일 것입니다.
다음으로 저장소를 연결하고 이를 사용하여 일부 책에 액세스해야 합니다. 다음 목록(src/main/java/guides/caching/CachingApplication.java)에서는 이를 수행하는 방법을 보여줍니다.
package guides.caching;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CachingApplication {
public static void main(String[] args) {
SpringApplication.run(CachingApplication.class, args);
}
}
또한 BookRepository
를 삽입하고 다른 인수로 여러 번 호출하는 CommandLineRunner
가 필요합니다. 다음 목록(src/main/java/guides/caching/AppRunner.java)은 해당 클래스를 보여줍니다.
package guides.caching;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class AppRunner implements CommandLineRunner {
private static final Logger logger =
LoggerFactory.getLogger(AppRunner.class);
private final BookRepository bookRepository;
public AppRunner(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
@Override
public void run(String... args) throws Exception {
logger.info("..... Fetching books");
logger.info("isbn-1234 -->" + bookRepository.getByIsbn("isbn-1234"));
logger.info("isbn-4567 -->" + bookRepository.getByIsbn("isbn-4567"));
logger.info("isbn-1234 -->" + bookRepository.getByIsbn("isbn-1234"));
logger.info("isbn-4567 -->" + bookRepository.getByIsbn("isbn-4567"));
logger.info("isbn-1234 -->" + bookRepository.getByIsbn("isbn-1234"));
logger.info("isbn-1234 -->" + bookRepository.getByIsbn("isbn-1234"));
}
}
이 시점에서 응용 프로그램을 실행하려고 하면 동일한 책을 여러 번 검색하더라도 속도가 상당히 느린 것을 알 수 있습니다. 다음 샘플 출력은 (의도적으로 끔찍한) 코드에서 생성된 3초 지연을 보여줍니다.
캐싱을 활성화하면 상황을 개선할 수 있습니다.
이제 책이 책 캐시 내에 캐시되도록 SimpleBookRepository
에서 캐싱을 활성화할 수 있습니다. 다음 목록(src/main/java/guides/caching/SimpleBookRepository.java)은 저장소 정의를 보여줍니다.
package guides.caching;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
@Component
public class SimpleBookRepository implements BookRepository {
@Override
@Cacheable("books")
public Book getByIsbn(String isbn) {
simulateSlowService();
return new Book(isbn, "Some book");
}
// Don't do this at home
private void simulateSlowService() {
try {
long time = 3000L;
Thread.sleep(time);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
}
이제 다음 예제(src/main/java/guides/caching/CachingApplication.java)에서 수행 방법을 보여주듯이 캐싱 주석 처리를 활성화해야 합니다.
package guides.caching;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class CachingApplication {
public static void main(String[] args) {
SpringApplication.run(CachingApplication.class, args);
}
}
@EnableCaching
주석은 모든 Spring Bean을 검사하여 공용 메서드에 캐싱 주석이 있는지 검사하는 사후 프로세서(post-processor)를 트리거합니다. 이러한 주석이 발견되면 메서드 호출을 가로채고 그에 따라 캐싱 동작을 처리하기 위해 프록시가 자동으로 생성됩니다.
사후 프로세서는 @Cacheable
, @CachePut
및 @CacheEvict
주석을 처리합니다. 자세한 내용은 Javadoc 및 참조 가이드를 참조하세요.
@Cacheable
: 메서드의 결과를 캐시에 저장하고, 이후 같은 파라미터로 호출될 때 캐시된 결과를 반환합니다.@CachePut
: 메서드를 호출하고 그 결과를 캐시에 업데이트합니다. 기존 캐시 항목을 갱신합니다.@CacheEvict
: 지정된 캐시 항목을 제거합니다. 메서드 호출 후 캐시를 비웁니다.Spring Boot는 관련 캐시에 대한 공급자 역할을 하도록 적합한 CacheManager
를 자동으로 구성합니다. 자세한 내용은 Spring Boot 설명서를 참조하세요.
우리 샘플은 특정 캐싱 라이브러리를 사용하지 않으므로 캐시 저장소는 ConcurrentHashMap
을 사용하는 간단한 대체입니다. 캐싱 추상화는 광범위한 캐시 라이브러리를 지원하며 JSR-107(JCache)과 완벽하게 호환됩니다.
CacheManager
: 스프링이 캐시 관리를 담당하는 인터페이스입니다. 캐시 관련 동작을 수행하며, 실제 캐시 구현체와의 상호 작용을 담당합니다.ConcurrentHashMap
: 스프링 캐시 추상화에서 가장 간단한 캐시 저장소 중 하나입니다. 실제로는 간단한 메모리 기반의 해시 맵으로, 캐시 데이터를 메모리에 보관합니다.이제 캐싱이 활성화되었으므로 애플리케이션을 다시 실행하고 동일한 ISBN이 있거나 없는 추가 호출을 추가하여 차이점을 확인할 수 있습니다. 그것은 큰 변화를 가져올 것입니다. 다음 목록은 캐싱이 활성화된 출력을 보여줍니다.
이전 샘플 출력에서 책을 처음 검색하는 데는 여전히 3초가 걸립니다. 그러나 동일한 책에 대한 두 번째 및 그 이후의 시간은 훨씬 빠르며 이는 캐시가 해당 작업을 수행하고 있음을 나타냅니다.