Spring's Road to God Capítulo 40: Uso de caché (@EnableCaching, @Cacheable, @CachePut, @CacheEvict, @Caching, @CacheConfig)

Spring's Road to God Capítulo 40: Uso de caché (@EnableCaching, @Cacheable, @CachePut, @CacheEvict, @Caching, @CacheConfig)

Este artículo explica principalmente el uso de caché en primavera.

fondo

Todo el mundo conoce el almacenamiento en caché, se utiliza principalmente para mejorar la velocidad de consulta del sistema.

Por ejemplo, la información de detalles del producto en el comercio electrónico, esta información generalmente no cambia con frecuencia pero se accede con frecuencia, podemos sacar esta información de la base de datos y ponerla en el caché (como redis, memoria local), al obtenerla , Consígalo de la memoria caché primero. Si no hay memoria caché, obténgala de la base de datos y luego tírela a la memoria caché. Cuando se cambia la información del producto, puede eliminar la información en la memoria caché o arrojar los datos más recientes a la memoria caché. caché. .

Spring proporciona un conjunto completo de soluciones de almacenamiento en caché, que son muy fáciles de usar. El almacenamiento en caché se utiliza principalmente a través de anotaciones. Hay 5 anotaciones de uso común, y las presentaremos una por una.

Este artículo utilizará muchas expresiones ortográficas. Si no está familiarizado con este consejo, eche un vistazo primero: Explicación detallada de Spel en Spring

@EnableCaching: habilitar el almacenamiento en caché

Para habilitar la función de almacenamiento en caché, esta anotación debe agregarse a la clase de configuración. Después de esta anotación, Spring sabe que necesita usar la función de almacenamiento en caché, y otras anotaciones relacionadas con el almacenamiento en caché serán efectivas. Spring se implementa principalmente a través de aop, a través de aop Para interceptar el método que necesita usar el caché para realizar la función de caché.

@Cacheable: dar función de caché

efecto

@Cacheable se puede marcar en un método o en una clase. Cuando se marca en un método, significa que el método admite el almacenamiento en caché. Cuando se marca en una clase, significa que todos los métodos de esta clase admiten el almacenamiento en caché. Para un método que admita el almacenamiento en caché, Spring almacenará en caché su valor de retorno después de que se llame para garantizar que la próxima vez que se ejecute el método con los mismos parámetros, el resultado se pueda obtener directamente del caché sin necesidad de ejecutar el método nuevamente. Spring almacena en caché el valor de retorno de un método con un par clave-valor, y el valor es el resultado de retorno del método En cuanto a la clave, Spring admite dos estrategias, la estrategia predeterminada y la estrategia personalizada, que se explicarán más adelante. Cabe señalar que cuando se llama a un método que admite el almacenamiento en caché dentro del objeto, la función de almacenamiento en caché no se activará. @Cacheable puede especificar tres atributos, valor, clave y condición.

@Target({
    
    ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {
    
    
 String[] value() default {
    
    };
 String[] cacheNames() default {
    
    };
 String key() default "";
 String condition() default "";
 String unless() default "";
}

atributo de valor: especifique el nombre de caché

El valor tiene la misma función que el atributo cacheNames, y se debe especificar uno de ellos, indicando en qué Caché se almacenará el valor de retorno del método actual, correspondiente al nombre del Caché. Puede ser una caché o varias cachés, y es una matriz cuando es necesario especificar varias cachés.

El caché se puede imaginar como un HashMap. Puede haber muchos cachés en el sistema, y ​​cada caché tiene un nombre. Debe especificar en qué caché desea colocar el valor de retorno del método por el nombre del caché.

Caso 1

El siguiente método de lista agrega la función de almacenamiento en caché y coloca el resultado cache1en el caché.

package com.javacode2018.cache.demo1;

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

@Component
public class ArticleService {
    
    

    @Cacheable(cacheNames = {
    
    "cache1"})
    public List<String> list() {
    
    
        System.out.println("获取文章列表!");
        return Arrays.asList("spring", "mysql", "java高并发", "maven");
    }
}

Aquí hay una clase de configuración MainConfig1que debe@EnableCaching anotarse para habilitar el almacenamiento en caché .

Luego se debe definir un bean en la clase de configuración: Cache Manager, el tipo es CacheManager, CacheManageresta es una interfaz, hay varias implementaciones (como usar redis, ConcurrentMap para almacenar información de caché), aquí usamos ConcurrentMapCacheManager, internamente usamos ConcurrentHashMap para directamente almacenar información de caché en la memoria jvm local, pero el entorno en línea generalmente tiene la forma de un clúster, que se puede realizar a través de redis.El siguiente artículo presenta la integración de spring cache con redis.

package com.javacode2018.cache.demo1;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@EnableCaching //@0
@ComponentScan
@Configuration
public class MainConfig1 {
    
    

    //@1:缓存管理器
    @Bean
    public CacheManager cacheManager() {
    
    
        //创建缓存管理器(ConcurrentMapCacheManager:其内部使用ConcurrentMap实现的),构造器用来指定缓存的名称,可以指定多个
        ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager("cache1");
        return cacheManager;
    }

}

listVen a una clase de prueba, llama al método dos veces para ver el efecto.

package com.javacode2018.cache;

import com.javacode2018.cache.demo1.ArticleService;
import com.javacode2018.cache.demo1.MainConfig1;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class CacheTest {
    
    

    @Test
    public void test1() {
    
    
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(MainConfig1.class);
        context.refresh();
        ArticleService articleService = context.getBean(ArticleService.class);
        System.out.println(articleService.list());
        System.out.println(articleService.list());
    }

}

producción

获取文章列表!
[spring, mysql, java高并发, maven]
[spring, mysql, java高并发, maven]

Como se puede ver en la primera línea, la primera vez que ingresó al método de lista, la segunda vez no ingresó al método de lista, sino que lo obtuvo del caché.

atributo clave: clave personalizada

El atributo clave se usa para especificar la clave correspondiente al resultado de retorno del método de caché Spring.Como se mencionó anteriormente, puede entender Caché como un mapa hash, y el caché se almacena en el mapa hash en forma de clave-> valor, y valor es el valor que debe almacenarse en caché (es decir, el método El valor de retorno)

El atributo clave admite expresiones SpEL; cuando no especificamos este atributo, Spring utilizará la estrategia predeterminada para generar la clave (org.springframework.cache.interceptor.SimpleKeyGenerator), y el parámetro del método creará la clave de forma predeterminada.

La estrategia personalizada significa que podemos especificar nuestra clave a través de la expresión SpEL. La expresión SpEL aquí puede usar parámetros de método y sus atributos correspondientes. Cuando usamos parámetros de método, podemos usar directamente "#nombre de parámetro" o "índice de parámetro #p".

Spring también nos proporciona un objeto raíz que puede usarse para generar una clave, a través del cual podemos obtener la siguiente información.

Nombre del Atributo describir ejemplo
métodoNombre nombre del método actual #root.métodoNombre
método método actual #raíz.método.nombre
objetivo el objeto actualmente llamado #raíz.objetivo
claseobjetivo La clase del objeto actualmente llamado #root.targetClass
argumentos matriz de parámetros del método actual #raíz.argumentos[0]
cachés Caché utilizada por el método llamado actualmente #raíz.cachés[0].nombre

Aquí nos fijamos principalmente en las estrategias personalizadas.

Caso 2

Agregue el siguiente código a ArticleService

@Cacheable(cacheNames = {
    
    "cache1"}, key = "#root.target.class.name+'-'+#page+'-'+#pageSize")
public String getPage(int page, int pageSize) {
    
    
    String msg = String.format("page-%s-pageSize-%s", page, pageSize);
    System.out.println("从db中获取数据:" + msg);
    return msg;
}

com.javacode2018.cache.CacheTestAgregar caso de prueba

@Test
public void test2() {
    
    
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(MainConfig1.class);
    context.refresh();
    ArticleService articleService = context.getBean(ArticleService.class);
    
    //page=1,pageSize=10调用2次
    System.out.println(articleService.getPage(1, 10));
    System.out.println(articleService.getPage(1, 10));
    
    //page=2,pageSize=10调用2次
    System.out.println(articleService.getPage(2, 10));
    System.out.println(articleService.getPage(2, 10));

    {
    
    
        System.out.println("下面打印出cache1缓存中的key列表");
        ConcurrentMapCacheManager cacheManager = context.getBean(ConcurrentMapCacheManager.class);
        ConcurrentMapCache cache1 = (ConcurrentMapCache) cacheManager.getCache("cache1");
        cache1.getNativeCache().keySet().stream().forEach(System.out::println);
    }
}

ejecutar salida

从db中获取数据:page-1-pageSize-10
page-1-pageSize-10
page-1-pageSize-10
从db中获取数据:page-2-pageSize-10
page-2-pageSize-10
page-2-pageSize-10
下面打印出cache1缓存中的key列表
com.javacode2018.cache.demo1.ArticleService-getPage-1-10
com.javacode2018.cache.demo1.ArticleService-getPage-2-10

atributo de condición: controla las condiciones de uso del caché

A veces, es posible que deseemos que la consulta no vaya a la caché, y los resultados devueltos no deben almacenarse en caché al mismo tiempo, entonces podemos usar el atributo de condición para lograrlo. El atributo de condición está vacío de forma predeterminada, lo que significa que todos las situaciones de llamada se almacenarán en caché, y su valor se pasa a través de la expresión ortográfica Para especificar, cuando es verdadero , significa intentar obtenerlo primero del caché; si no existe en el caché, solo se necesita el método, y el valor de retorno del método se arroja a la memoria caché; cuando es falso , la memoria caché no se usa, y el método se ejecuta directamente, y el resultado devuelto no se arrojará a la memoria caché.

Su hechizo de valor se escribe de manera similar al atributo clave.

Caso 3

Agregue el siguiente código a ArticleService. El segundo caché de parámetros del método se usa para controlar si se va al caché, y el valor de la condición se especifica como#cache

/**
 * 通过文章id获取文章
 *
 * @param id    文章id
 * @param cache 是否尝试从缓存中获取
 * @return
 */
@Cacheable(cacheNames = "cache1", key = "'getById'+#id", condition = "#cache")
public String getById(Long id, boolean cache) {
    
    
    System.out.println("获取数据!");
    return "spring缓存:" + UUID.randomUUID().toString();
}

Vaya a un caso de prueba, llame al método getById 4 veces, las primeras 2 veces y el último parámetro de caché son verdaderos, y la tercera vez es falso

@Test
public void test3() {
    
    
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(MainConfig1.class);
    context.refresh();
    ArticleService articleService = context.getBean(ArticleService.class);

    System.out.println(articleService.getById(1L, true));
    System.out.println(articleService.getById(1L, true));
    System.out.println(articleService.getById(1L, false));
    System.out.println(articleService.getById(1L, true));
}

ejecutar salida

获取数据!
spring缓存:27e7c11a-26ed-4c8b-8444-78257daafed5
spring缓存:27e7c11a-26ed-4c8b-8444-78257daafed5
获取数据!
spring缓存:05ff7612-29cb-4863-b8bf-d1b7c2c192b7
spring缓存:27e7c11a-26ed-4c8b-8444-78257daafed5

Se puede ver en el resultado que la primera y la tercera vez ingresaron al método, mientras que 2 y 4 abandonaron el caché, y los resultados se arrojaron al caché después de la primera ejecución, por lo que 2 y 4 son 2 El resultado obtenido el segundo El tiempo es el mismo que la primera vez.

A menos que atributo: controla si el resultado debe ser arrojado a la memoria caché.

Expresión SpEL utilizada para anular el almacenamiento en caché del método. A diferencia de la condición, esta expresión se evalúa después de llamar al método, por lo que se puede hacer referencia al resultado. El valor predeterminado es "", lo que significa que la memoria caché nunca queda obsoleta.

La premisa es que si la condición está vacía o es verdadera, a menos que sea válido. Cuando la condición es falsa, a menos que no sea válido. Si a menos que sea verdadero, el resultado devuelto por el método no se guardará en la memoria caché; a menos que sea falso, el método devuelve El resultado se arrojará al centro del caché.

Su hechizo de valor se escribe de manera similar al atributo clave.

Caso 4

Tomemos un caso a continuación. Cuando el resultado devuelto es nulo, no almacene en caché el resultado. Agregue el siguiente código a ArticleService

Map<Long, String> articleMap = new HashMap<>();
/**
 * 获取文章,先从缓存中获取,如果获取的结果为空,不要将结果放在缓存中
 *
 * @param id
 * @return
 */
@Cacheable(cacheNames = "cache1", key = "'findById'+#id", unless = "#result==null")
public String findById(Long id) {
    
    
    this.articleMap.put(1L, "spring系列");
    System.out.println("----获取文章:" + id);
    return articleMap.get(id);
}

Aquí hay un caso de prueba, llame a findById 4 veces, las primeras 2 veces tienen datos, las últimas 2 veces devuelven un valor nulo e imprimen la clave en el caché

@Test
public void test4() {
    
    
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(MainConfig1.class);
    context.refresh();
    ArticleService articleService = context.getBean(ArticleService.class);

    System.out.println(articleService.findById(1L));
    System.out.println(articleService.findById(1L));
    System.out.println(articleService.findById(3L));
    System.out.println(articleService.findById(3L));

    {
    
    
        System.out.println("下面打印出缓cache1缓存中的key列表");
        ConcurrentMapCacheManager cacheManager = context.getBean(ConcurrentMapCacheManager.class);
        ConcurrentMapCache cache1 = (ConcurrentMapCache) cacheManager.getCache("cache1");
        cache1.getNativeCache().keySet().stream().forEach(System.out::println);
    }
}

ejecutar salida

----获取文章:1
spring系列
spring系列
----获取文章:3
null
----获取文章:3
null
下面打印出缓cache1缓存中的key列表
findById1

Se puede ver que el resultado del artículo id 1 se almacena en caché, pero el resultado del archivo id 3 no se almacena en caché.

condición vs a menos que

Hay 2 puntos en el proceso de uso del caché:

  1. Consultar si hay datos en el caché
  2. Si no hay datos en el caché, ejecute el método de destino y luego arroje el resultado del método en el caché.

Estos dos puntos se intervienen en primavera por condición y menos.

Los dos procesos por encima del alcance de la condición , cuando son verdaderos , intentarán obtener datos del caché, si no, ejecutarán el método y luego arrojarán el valor devuelto del método al caché; si es falso, llame directamente al método de destino, y los resultados no se colocan en caché.

El "menos" solo es válido cuando la condición es verdadera . Se usa para juzgar si el resultado no debe ser arrojado a la caché en el segundo punto anterior. Si es verdadero, el resultado no será arrojado a la caché. Si es falso, el resultado será Tíralo a la memoria caché y, a menos que puedas usar la expresión ortográfica para obtener el valor de retorno del método a través de **#resultado**.

@CachePut: poner el resultado en el caché

efecto

@CachePut también se puede marcar en una clase o método. El método marcado se llamará cada vez, y luego de que se ejecute el método, el resultado del método se arrojará a la memoria caché; cuando se marca en una clase, es equivalente a todos métodos de la clase Anotado @CachePut.

Hay 3 casos, el resultado no se arrojará al caché

  1. Cuando el método arroja
  2. Cuando el resultado de la evaluación de la condición es falso
  3. Cuando el resultado de la evaluación de a menos que sea verdadero

El código fuente es similar a Cacheable y contiene parámetros similares.

@Target({
    
    ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CachePut {
    
    
 String[] value() default {
    
    };
 String[] cacheNames() default {
    
    };
 String key() default "";
 String condition() default "";
 String unless() default "";
}
  • value y cacheNames: se utiliza para especificar el nombre de caché, puede especificar varios
  • clave: clave en caché, expresión ortográfica, consulte la clave en @Cacheable
  • condition: expresión ortográfica, escrita de la misma manera que la condición en @Cacheable, cuando está vacía o el resultado del cálculo es verdadero , el valor de retorno del método se arrojará a la memoria caché; de lo contrario, el resultado no se arrojará a la memoria caché. el caché
  • a menos: cuando la condición está vacía o el resultado del cálculo es verdadero, a menos que surta efecto; verdadero : el resultado no se arrojará a la memoria caché, falso : el resultado se arrojará a la memoria caché.

Caso 5

Tomemos un caso para implementar la operación de agregar un artículo y luego colocar el artículo en el caché. Tenga en cuenta que los nombres de caché y los parámetros clave en @CachePut a continuación son los mismos que en @Cacheable en el método findById en el Caso 4, lo que indica que comparten un caché Lo mismo es cierto para la clave, por lo que después de ejecutar el método add, llame al método findById para obtener los datos directamente del caché.

@CachePut(cacheNames = "cache1", key = "'findById'+#id")
public String add(Long id, String content) {
    
    
    System.out.println("新增文章:" + id);
    this.articleMap.put(id, content);
    return content;
}

caso de prueba

@Test
public void test5() {
    
    
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(MainConfig1.class);
    context.refresh();
    ArticleService articleService = context.getBean(ArticleService.class);

    //新增3个文章,由于add方法上面有@CachePut注解,所以新增之后会自动丢到缓存中
    articleService.add(1L, "java高并发系列");
    articleService.add(2L, "Maven高手系列");
    articleService.add(3L, "MySQL高手系列");

    //然后调用findById获取,看看是否会走缓存
    System.out.println("调用findById方法,会尝试从缓存中获取");
    System.out.println(articleService.findById(1L));
    System.out.println(articleService.findById(2L));
    System.out.println(articleService.findById(3L));

    {
    
    
        System.out.println("下面打印出cache1缓存中的key列表");
        ConcurrentMapCacheManager cacheManager = context.getBean(ConcurrentMapCacheManager.class);
        ConcurrentMapCache cache1 = (ConcurrentMapCache) cacheManager.getCache("cache1");
        cache1.getNativeCache().keySet().stream().forEach(System.out::println);
    }
}

ejecutar salida

新增文章:1
新增文章:2
新增文章:3
调用findById方法,会尝试从缓存中获取
java高并发系列
Maven高手系列
MySQL高手系列
下面打印出缓cache1缓存中的key列表
findById3
findById2
findById1

Eche un vistazo a la salida y luego mire el código para el método findById

@Cacheable(cacheNames = "cache1", key = "'findById'+#id", unless = "#result==null")
public String findById(Long id) {
    
    
    this.articleMap.put(1L, "spring系列");
    System.out.println("----获取文章:" + id);
    return articleMap.get(id);
}

No hay ----dicho contenido en la salida, lo que indica que el resultado obtenido al llamar al método findById se obtiene de la memoria caché.

@CacheEvict: limpieza de caché

efecto

Usado para borrar el caché, @CacheEvict también se puede marcar en la clase o el método. Si está marcado en el método, cuando se llama al método de destino, se borrará el caché especificado; cuando se marca en la clase, es equivalente a todos los métodos en la clase @CacheEvict están marcados en él.

Echemos un vistazo al código fuente y echemos un vistazo a los comentarios de cada parámetro en detalle.

public @interface CacheEvict {
    
    

    /**
     * cache的名称,和cacheNames效果一样
     */
    String[] value() default {
    
    };

    /**
     * cache的名称,和cacheNames效果一样
     */
    String[] cacheNames() default {
    
    };

    /**
     * 缓存的key,写法参考上面@Cacheable注解的key
     */
    String key() default "";

    /**
     * @CacheEvict 注解生效的条件,值为spel表达式,写法参考上面 @Cacheable注解中的condition
     */
    String condition() default "";

    /**
     * 是否清理 cacheNames 指定的缓存中的所有缓存信息,默认是false
     * 可以将一个cache想象为一个HashMap,当 allEntries 为true的时候,相当于HashMap.clear()
     * 当 allEntries 为false的时候,只会干掉key对应的数据,相当于HashMap.remove(key)
     */
    boolean allEntries() default false;

    /**
     * 何事执行清除操作(方法执行前 or 方法执行成功之后)
     * true:@CacheEvict 标注的方法执行之前,执行清除操作
     * false:@CacheEvict 标注的方法执行成功之后,执行清除操作,当方法弹出异常的时候,不会执行清除操作
     */
    boolean beforeInvocation() default false;
}

atributo de condición

Las condiciones bajo las cuales la anotación @CacheEvict surte efecto, el valor es una expresión ortográfica y el método de escritura se refiere a la condición en la anotación @Cacheable anterior

¿Qué cachés se borran?

De forma predeterminada, se borrará la información de la memoria caché especificada por el parámetro clave en la memoria caché especificada por cacheNames.

Pero cuando allEntries es verdadero, se borrará toda la información de caché en el caché especificado por cacheNames.

¿Cuándo se debe borrar el caché?

Esto está controlado por el parámetro beforeInvocation, que es falso de forma predeterminada. De forma predeterminada , la operación de limpieza se realizará después de que el método de destino se ejecute con éxito. Si el método arroja una excepción, la operación de limpieza no se realizará;

Si beforeInvocation es true , la operación de limpieza de caché se realizará antes de que se ejecute el método y no se ejecutará después de que se ejecute el método.

Caso 6

Agregue un nuevo método en ArticleService y márquelo con @CacheEvict. Después de ejecutar este método, key=findById+参数idse borrará la información de caché en cache1. Tenga en cuenta que los valores de los parámetros cacheNames y key son los mismos que los de los parámetros en findById .

@CacheEvict(cacheNames = "cache1", key = "'findById'+#id") //@1
public void delete(Long id) {
    
    
    System.out.println("删除文章:" + id);
    this.articleMap.remove(id);
}

Se agregan nuevos casos de prueba, los comentarios son más claros, por lo que no los explicaré.

@Test
public void test6() {
    
    
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(MainConfig1.class);
    context.refresh();
    ArticleService articleService = context.getBean(ArticleService.class);

    //第1次调用findById,缓存中没有,则调用方法,将结果丢到缓存中
    System.out.println(articleService.findById(1L));
    //第2次调用findById,缓存中存在,直接从缓存中获取
    System.out.println(articleService.findById(1L));

    //执行删除操作,delete方法上面有@CacheEvict方法,会清除缓存
    articleService.delete(1L);

    //再次调用findById方法,发现缓存中没有了,则会调用目标方法
    System.out.println(articleService.findById(1L));
}

ejecutar salida

----获取文章:1
spring系列
spring系列
删除文章:1
----获取文章:1
spring系列

Llame a findById 3 veces, la primera vez, no hay nada en la memoria caché, por lo que ingresa al método y luego arroja el resultado a la memoria caché, la segunda vez está en la memoria caché, por lo que se obtiene de la memoria caché, y luego el método de eliminación se ejecuta, este método se ejecuta Después de la finalización, la información del artículo con la identificación del artículo de 1L en el caché se borrará y, finalmente, el método findById se ejecuta por tercera vez. En este momento, no se encuentran datos en el caché, y luego ingresa al método de destino, y el método de destino genera el contenido ----.

@Caching: grupo de anotaciones de caché

Cuando usamos múltiples anotaciones de @Cacheable, @CachePut y @CacheEvic en una clase o en el mismo método al mismo tiempo, podemos usar la anotación @Caching para lograr esto.

@Target({
    
    ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Caching {
    
    

 Cacheable[] cacheable() default {
    
    };

 CachePut[] put() default {
    
    };

 CacheEvict[] evict() default {
    
    };

}

@CacheConfig: extraer configuración común

Esta anotación está marcada en la clase y los parámetros públicos de varias otras anotaciones de caché (@Cacheable, @CachePut y @CacheEvic) se pueden extraer y colocar en @CacheConfig.

Por ejemplo, cuando hay muchos métodos en una clase que necesitan usar estas anotaciones de caché (@Cacheable, @CachePut y @CacheEvic), puede echar un vistazo al código fuente de estas tres anotaciones. Tienen muchos atributos comunes, tales como: cacheNames, keyGenerator, cacheManager, cacheResolver, si estos valores de atributo son los mismos, se pueden extraer y colocar en @CacheConfig, pero estas anotaciones (@Cacheable, @CachePut y @CacheEvic) también pueden especificar el valor de el atributo en @CacheConfig los valores de atributo se sobrescriben.

@CacheConfig(cacheNames = "cache1")
public class ArticleService {
    
    
    @Cacheable(key = "'findById'+#id")
    public String findById(Long id) {
    
    
        this.articleMap.put(1L, "spring系列");
        System.out.println("----获取文章:" + id);
        return articleMap.get(id);
    }
}

principio

El caché en primavera se realiza principalmente mediante aop en primavera. A través de Aop, se crea un objeto proxy para el bean que necesita usar el caché, y el objeto proxy intercepta la ejecución del método de destino para realizar la función de caché.

El foco está en esta anotación, que se puede ver @EnableCachingdesde esta anotación@Import

@Import(CachingConfigurationSelector.class)
public @interface EnableCaching {
    
    
}

Finalmente, se creará un objeto proxy para el bean que necesita usar el caché y se agregará un interceptor al proxy. El método org.springframework.cache.interceptor.CacheInterceptoren esta clase invokees la clave e interceptará la ejecución de todos los métodos de destino relacionados con el caché. Puedes echar un vistazo más de cerca.

Resumir

Ya hay 40 artículos en la serie Spring, y realmente no es fácil quedarse conmigo hasta ahora.

Para aquellos que no han terminado de leerlo, sugiero que lo lean en orden, lo mejor es leer los artículos en orden, y los puntos de conocimiento antes y después son dependientes.

Si ha leído los artículos anteriores, entonces no necesito presentar el principio de este artículo, puede entenderlo fácilmente usted mismo.

Código fuente del caso

https://gitee.com/javacode2018/spring-series

Transeúnte A Todos los códigos de casos de Java se pondrán en esto en el futuro, todos lo miren, pueden seguir prestando atención a la dinámica.

Fuente: https://mp.weixin.qq.com/s?__biz=MzA5MTkxMDQ4MQ==&mid=2648936253&idx=2&sn=fe74d8130a85dd70405a80092b2ba48c&scene=21#wechat_redirect

Supongo que te gusta

Origin blog.csdn.net/china_coding/article/details/130778193
Recomendado
Clasificación