Um guia para armazenamento em cache na primavera

Um guia para armazenamento em cache na primavera

1. A abstração do cache?

Neste artigo, vamos mostrar comouse the Caching Abstraction in Spring - e, de modo geral, melhorar o desempenho do seu sistema.

Ativaremos o cache simples para alguns exemplos de métodos do mundo real e discutiremos como podemos melhorar de forma prática o desempenho dessas chamadas por meio do gerenciamento inteligente de cache.

Leitura adicional:

Exemplo de Ehcache de inicialização de primavera

Um guia rápido e prático para usar o Spring com Ehcache.

Read more

Despejo de cache na inicialização do Spring

Aprenda como invalidar caches com o Spring Boot.

Read more

2. Começando

A abstração de cache de núcleo fornecida pelo Spring reside no smodulespring-context . Portanto, ao usar o Maven, nossopom.xml deve conter a seguinte dependência:


    org.springframework
    spring-context
    5.1.8.RELEASE

Curiosamente, há outro módulo denominadospring-context-support, que fica no topo dospring-context module e fornece mais algunsCacheManagers apoiado porEhCache ouCaffeine. Se você for usá-los como armazenamento em cache, use ospring-context-support module em vez disso:


    org.springframework
    spring-context-support
    5.1.8.RELEASE

Como o módulospring-context-support depende transitivamente dospring-context module, não há necessidade de uma declaração de dependência separada para ospring-context.

2.1. Spring Boot

Se você for um usuário Spring Boot, use o pacotespring-boot-starter-cache starter para adicionar facilmente as dependências de cache:


    org.springframework.boot
    spring-boot-starter-cache

Sob o capô, o starter traz o smodulespring-context-support .

3. Ativar cache

Para habilitar o armazenamento em cache, o Spring faz bom uso de anotações, como ativar qualquer outro recurso de nível de configuração na estrutura.

O recurso de cache pode ser habilitado declarativamente, simplesmente adicionando a anotação@EnableCaching a qualquer uma das classes de configuração:

@Configuration
@EnableCaching
public class CachingConfig {

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

Você pode, é claro, a configuração deenable cache management with XML também:


    

    
        
            
                
            
        
    

Note: Depois de habilitar o cache - para a configuração mínima - nósmust registramos acacheManager.

Using XML does enable more flexible options para configurar o cache - você pode especificar seu próprio Cache-Manager, Cache-Resolver, Error-Handler e, geralmente, usar opções de personalização mais avançadas (refer to the Javadoc para mais detalhes).

3.1. Spring Boot

Ao usar o Spring Boot, a mera presença do pacote inicial no caminho de classe junto com aEnableCaching annotation registraria o mesmoConcurrentMapCacheManager. So, não há necessidade de uma declaração de bean separada.

Além disso, podemos personalizar oauto-configuredCacheManager using um ou maisCacheManagerCustomizer<T> beans:

@Component
public class SimpleCacheCustomizer
  implements CacheManagerCustomizer {

    @Override
    public void customize(ConcurrentMapCacheManager cacheManager) {
        cacheManager.setCacheNames(asList("users", "transactions"));
    }
}

A configuraçãoCacheAutoConfiguration auto seleciona esses personalizadores e os aplica aoCacheManager  atual antes de sua inicialização completa.

4. Use Cache com Anotações

Depois de ativar o cache, a próxima etapa é vincular o comportamento do cache aos métodos com anotações declarativas.

4.1. @Cacheable

A maneira mais simples de habilitar o comportamento de cache de um método é demarcá-lo com@Cacheablee parametrizá-lo com o nome do cache onde os resultados seriam armazenados:

@Cacheable("addresses")
public String getAddress(Customer customer) {...}

A chamadagetAddress() verificará primeiro o cacheaddresses antes de realmente chamar o método e, em seguida, armazenar em cache o resultado.

Embora na maioria dos casos, um cache seja suficiente, a estrutura Spring também suporta vários caches a serem passados ​​como parâmetros:

@Cacheable({"addresses", "directory"})
public String getAddress(Customer customer) {...}

____ Nesse caso, se qualquer um dos caches contiver o resultado necessário, o resultado será retornado e o método não será invocado.

4.2. @CacheEvict __

Agora, qual seria o problema em fazer todos os métodos@Cacheable?

O problema é o tamanho -we don’t want to populate the cache with values that we don’t need often. Os caches podem crescer muito grandes, muito rapidamente e poderíamos estar mantendo muitos dados antigos ou não utilizados.

A anotação@CacheEvict é usada para indicar a remoção de um ou mais / todos os valores - para que novos valores possam ser carregados no cache novamente:

@CacheEvict(value="addresses", allEntries=true)
public String getAddress(Customer customer) {...}

Aqui, estamos usando o parâmetro adicionalallEntries em conjunto com o cache a ser esvaziado - para limpar todas as entradas no cacheaddressese prepará-lo para novos dados.

__ 4.3. @CachePut

Embora@CacheEvict reduza a sobrecarga de pesquisa de entradas em um cache grande removendo entradas obsoletas e não utilizadas, idealmente, você desejaavoid evicting too much data out of the cache.

Em vez disso, você deseja atualizar de forma seletiva e inteligente as entradas sempre que forem alteradas.

Com a anotação@CachePut, você pode atualizar o conteúdo do cache sem interferir na execução do método. Ou seja, o método sempre seria executado e o resultado armazenado em cache.

@CachePut(value="addresses")
public String getAddress(Customer customer) {...}

A diferença entre@Cacheable e@CachePut é que@Cacheable iráskip running the method, enquanto@CachePut iráactually run the methode colocará seus resultados no cache.

4.4. @Caching

E se você quiser usar várias anotações do mesmo tipo para armazenar em cache um método. Veja o exemplo incorreto abaixo:

@CacheEvict("addresses")
@CacheEvict(value="directory", key=customer.name)
public String getAddress(Customer customer) {...}

O código acima falharia ao compilar, pois o Java não permite que várias anotações do mesmo tipo sejam declaradas para um determinado método.

A solução alternativa para o problema acima seria:

@Caching(evict = {
  @CacheEvict("addresses"),
  @CacheEvict(value="directory", key="#customer.name") })
public String getAddress(Customer customer) {...}

Conforme mostrado no trecho de código acima, você podegroup multiple caching annotations com@Caching e usá-lo para implementar sua própria lógica de cache personalizada.

4.5. @CacheConfig

Com a anotação@CacheConfig, você podestreamline some of the cache configuration into a single place – at the class level - para que não precise declarar coisas várias vezes:

@CacheConfig(cacheNames={"addresses"})
public class CustomerDataService {

    @Cacheable
    public String getAddress(Customer customer) {...}

5. Cache Condicional

Às vezes, o armazenamento em cache pode não funcionar bem para um método em todas as situações.

Por exemplo - reutilizando nosso exemplo da anotação@CachePut - isso executará o método e também armazenará em cache os resultados todas as vezes:

@CachePut(value="addresses")
public String getAddress(Customer customer) {...}

5.1. Parâmetro de Condição

Agora - se quisermos mais controle sobre quando a anotação está ativa -@CachePut pode ser parametrizado com um parâmetro de condição que usa uma expressão SpEL para garantir que os resultados sejam armazenados em cache com base na avaliação dessa expressão:

@CachePut(value="addresses", condition="#customer.name=='Tom'")
public String getAddress(Customer customer) {...}

5.2. A menos que o parâmetro

Também podemos controlar o cachebased on the output of the method rather than the input - por meio do parâmetrounless:

@CachePut(value="addresses", unless="#result.length()<64")
public String getAddress(Customer customer) {...}

A anotação acima armazenaria em cache os endereços, a menos que tenham menos de 64 caracteres.

É importante saber que os parâmetrosconditioneunless podem ser usados ​​em conjunto com todas as anotações de cache.

Esse tipo de armazenamento em cache condicional pode ser bastante útil para gerenciar grandes resultados e personalizar o comportamento com base nos parâmetros de entrada, em vez de impor um comportamento genérico a todas as operações.

6. Cache declarativo baseado em XML

Caso você não tenha acesso ao código-fonte do seu aplicativo ou queira injetar o comportamento do cache externamente, você também pode usar o cache declarativo baseado em XML.

Aqui está a nossa configuração XML: