1. 캐시 추상화?
이 튜토리얼에서는 Spring에서 Caching Abstraction 을 사용하는 방법을 배우고 일반적으로 시스템 성능을 향상시킬 것입니다.
실제 메서드 예제에 대해 간단한 캐싱을 활성화하고 스마트 캐시 관리를 통해 이러한 호출의 성능을 실질적으로 개선 할 수있는 방법에 대해 논의 할 것입니다.
2. 시작하기
Spring에서 제공하는 핵심 캐싱 추상화는 spring-context 모듈에 있습니다. 따라서 Maven을 사용할 때 pom.xml 에는 다음 의존성이 포함되어야합니다.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.3</version>
</dependency>
흥미롭게도 spring-context-support 라는 또 다른 모듈이 있는데 , 이는 spring-context 모듈 위에 있으며 EhCache 또는 Caffeine 과 같은 지원을받는 몇 가지 CacheManagers를 더 제공합니다 . 이를 캐시 저장소로 사용하려면 대신 spring-context-support 모듈 을 사용해야합니다 .
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.3.3</version>
</dependency>
spring-context-support 모듈 은 spring-context 모듈에 전 이적으로 의존하기 때문에 spring-context 에 대한 별도의 의존성 선언이 필요하지 않습니다 .
2.1. Spring 부팅
Spring Boot를 사용하는 경우 spring-boot-starter-cache 스타터 패키지를 활용하여 캐싱 의존성을 쉽게 추가 할 수 있습니다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<version>2.4.0</version>
</dependency>
후드 아래에서 스타터는 spring-context-support 모듈을 가져옵니다 .
3. 캐싱 활성화
캐싱을 활성화하기 위해 Spring은 프레임 워크에서 다른 구성 수준 기능을 활성화하는 것과 마찬가지로 어노테이션을 잘 사용합니다.
구성 클래스에 @EnableCaching 어노테이션을 추가하기 만하면 캐싱 기능을 활성화 할 수 있습니다.
@Configuration
@EnableCaching
public class CachingConfig {
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("addresses");
}
}
물론 XML 구성으로 캐시 관리를 활성화 할 수도 있습니다.
<beans>
<cache:annotation-driven />
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean
class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
name="addresses"/>
</set>
</property>
</bean>
</beans>
참고 : 캐싱을 활성화 한 후 최소 설정을 위해 cacheManager 를 등록해야합니다 .
3.1. Spring Boot 사용
Spring Boot를 사용할 때 EnableCaching 어노테이션 과 함께 클래스 경로에 스타터 패키지 만 있으면 동일한 ConcurrentMapCacheManager 가 등록 됩니다. 따라서 별도의 빈 선언이 필요하지 않습니다.
또한 하나 이상의 CacheManagerCustomizer <T> Bean을 사용하여 자동 구성된 CacheManager 를 사용자 정의 할 수 있습니다 .
@Component
public class SimpleCacheCustomizer
implements CacheManagerCustomizer<ConcurrentMapCacheManager> {
@Override
public void customize(ConcurrentMapCacheManager cacheManager) {
cacheManager.setCacheNames(asList("users", "transactions"));
}
}
CacheAutoConfiguration 자동 구성 은 이러한 커 스터 마이저를 선택 하여 전체 초기화 전에 현재 CacheManager에 적용합니다 .
4. 어노테이션과 함께 캐싱 사용
캐싱을 활성화 한 후 다음 단계는 선언적 어노테이션을 사용하여 캐싱 동작을 메서드에 바인딩하는 것입니다.
4.1. @ 캐시 가능
메서드에 대한 캐싱 동작을 활성화하는 가장 간단한 방법은 @Cacheable 로 구분 하고 결과가 저장 될 캐시의 이름으로 매개 변수화하는 것입니다.
@Cacheable("addresses")
public String getAddress(Customer customer) {...}
getAddress에 () 호출은 먼저 캐시 확인합니다 주소를 실제로 메소드를 호출 한 후 결과를 캐싱하기 전에.
대부분의 경우 하나의 캐시로 충분하지만 Spring 프레임 워크는 매개 변수로 전달할 여러 캐시도 지원합니다.
@Cacheable({"addresses", "directory"})
public String getAddress(Customer customer) {...}
이 경우 캐시에 필요한 결과가 포함 된 경우 결과가 반환되고 메서드가 호출되지 않습니다.
4.2. @ CacheEvict
이제 모든 메소드를 @Cacheable 로 만드는 데 문제가 있습니까?
문제는 크기입니다. W 전자는 우리가 자주 필요가 없습니다 값으로 캐시를 채울 싶지 않아요 . 캐시는 상당히 커지고 빠르게 증가 할 수 있으며 오래되거나 사용되지 않는 많은 데이터를 보유 할 수 있습니다.
@CacheEvict 어노테이션을 사용하여 하나 이상의 / 모든 값을 제거하여 새 값을 캐시에 다시로드 할 수 있음을 나타낼 수 있습니다.
@CacheEvict(value="addresses", allEntries=true)
public String getAddress(Customer customer) {...}
여기서는 비울 캐시와 함께 allEntries 추가 매개 변수를 사용합니다 . 이렇게하면 캐시 주소 의 모든 항목이 지워지고 새 데이터를 준비합니다.
4.3. @ CachePut
@CacheEvict 는 오래된 항목과 사용하지 않는 항목을 제거하여 큰 캐시에서 항목을 찾는 오버 헤드를 줄이는 반면 , 캐시 에서 너무 많은 데이터 를 제거하지 않으려 고 합니다 .
대신 항목을 변경할 때마다 선택적으로 업데이트합니다.
으로 @CachePut의 어노테이션, 우리는 메소드 실행을 방해하지 않고 캐시의 내용을 업데이트 할 수 있습니다. 즉, 메서드가 항상 실행되고 결과가 캐시됩니다.
@CachePut(value="addresses")
public String getAddress(Customer customer) {...}
차이 @Cacheable 및 @CachePut는 점이다 @Cacheable이 됩니다 방법을 실행 건너 반면, @CachePut는 것입니다 실제로이 방법을 실행 한 후 캐시에 그 결과를 넣습니다.
4.4. @ 캐싱
메서드 캐싱에 동일한 유형의 여러 어노테이션을 사용하려면 어떻게해야합니까? 잘못된 예를 살펴 보겠습니다.
@CacheEvict("addresses")
@CacheEvict(value="directory", key=customer.name)
public String getAddress(Customer customer) {...}
Java는 주어진 메소드에 대해 동일한 유형의 여러 어노테이션을 선언 할 수 없기 때문에 위 코드는 컴파일에 실패합니다.
위의 문제에 대한 해결 방법은 다음과 같습니다.
@Caching(evict = {
@CacheEvict("addresses"),
@CacheEvict(value="directory", key="#customer.name") })
public String getAddress(Customer customer) {...}
위의 코드 스 니펫에서 볼 수 있듯이 @Caching 을 사용 하여 여러 캐싱 어노테이션 을 그룹화 하고이를 사용하여 자체 맞춤형 캐싱 로직을 구현할 수 있습니다.
4.5. @ CacheConfig
@CacheConfig 어노테이션을 사용하면 일부 캐시 구성을 클래스 수준의 단일 위치로 간소화 할 수 있으므로 여러 번 선언 할 필요가 없습니다.
@CacheConfig(cacheNames={"addresses"})
public class CustomerDataService {
@Cacheable
public String getAddress(Customer customer) {...}
5. 조건부 캐싱
경우에 따라 모든 상황에서 메서드에 대해 캐싱이 제대로 작동하지 않을 수 있습니다.
@CachePut 어노테이션 의 예제를 재사용 하면 메서드를 실행하고 매번 결과를 캐시합니다.
@CachePut(value="addresses")
public String getAddress(Customer customer) {...}
5.1. 조건 매개 변수
어노테이션이 활성 상태 일 때 더 많은 제어를 원하면 SpEL 표현식을 사용하는 조건 매개 변수로 @CachePut 을 매개 변수화 하고 해당 표현식 평가에 따라 결과가 캐시되도록 할 수 있습니다.
@CachePut(value="addresses", condition="#customer.name=='Tom'")
public String getAddress(Customer customer) {...}
5.2. 매개 변수가 아닌 경우
또한 without 매개 변수 를 통한 입력이 아닌 메소드의 출력을 기반으로 캐싱을 제어 할 수 있습니다 .
@CachePut(value="addresses", unless="#result.length()<64")
public String getAddress(Customer customer) {...}
위의 어노테이션은 주소가 64 자 미만이 아닌 경우 주소를 캐시합니다.
모든 캐싱 어노테이션과 함께 조건 및 비정상 매개 변수를 사용할 수 있다는 것을 아는 것이 중요합니다 .
이러한 종류의 조건부 캐싱은 큰 결과를 관리하는 데 매우 효과적 일 수 있습니다. 또한 모든 작업에 일반 동작을 적용하는 대신 입력 매개 변수를 기반으로 동작을 사용자 지정하는 데 유용합니다.
6. 선언적 XML 기반 캐싱
애플리케이션의 소스 코드에 액세스 할 수 없거나 캐싱 동작을 외부에 삽입하려는 경우 선언적 XML 기반 캐싱을 사용할 수도 있습니다.
다음은 XML 구성입니다.
<!-- the service that you wish to make cacheable -->
<bean id="customerDataService"
class="com.your.app.namespace.service.CustomerDataService"/>
<bean id="cacheManager"
class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean
class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
name="directory"/>
<bean
class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
name="addresses"/>
</set>
</property>
</bean>
<!-- define caching behavior -->
<cache:advice id="cachingBehavior" cache-manager="cacheManager">
<cache:caching cache="addresses">
<cache:cacheable method="getAddress" key="#customer.name"/>
</cache:caching>
</cache:advice>
<!-- apply the behavior to all the implementations of CustomerDataService interface->
<aop:config>
<aop:advisor advice-ref="cachingBehavior"
pointcut="execution(* com.your.app.namespace.service.CustomerDataService.*(..))"/>
</aop:config>
7. 자바 기반 캐싱
다음은 동등한 Java 구성입니다.
@Configuration
@EnableCaching
public class CachingConfig {
@Bean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(
new ConcurrentMapCache("directory"),
new ConcurrentMapCache("addresses")));
return cacheManager;
}
}
그리고 다음은 CustomerDataService입니다 .
@Component
public class CustomerDataService {
@Cacheable(value = "addresses", key = "#customer.name")
public String getAddress(Customer customer) {
return customer.getAddress();
}
}
8. 요약
이 기사에서 우리는 Spring의 캐싱의 기초와 어노테이션으로 추상화를 잘 활용하는 방법에 대해 논의했다.
이 기사의 전체 구현은 GitHub 프로젝트 에서 찾을 수 있습니다 .
- https://docs.spring.io/spring-framework/docs/current/reference/html
- https://www.baeldung.com/spring-cache-tutorial
'Java' 카테고리의 다른 글
OkHttp 가이드 (0) | 2021.03.11 |
---|---|
Keycloak과 함께 사용자 지정 사용자 공급자 사용 (0) | 2021.03.11 |
Java 8의 기능 인터페이스 (0) | 2021.03.10 |
스프링 부트의 활성 및 준비 상태 프로브 (0) | 2021.03.10 |
스트림을 사용하여Map 작업 (0) | 2021.03.10 |