Технология кэширования Spring Boot

Spring Boot

Spring определяет интерфейсы CacheManager и Cache для унификации различных технологий кэширования. Например, JCache, EhCache, Hazelcast, Guava, Redis и т. д. При использовании Spring для интеграции Cache нам необходимо зарегистрировать Bean реализованного CacheManager. Spring Boot по умолчанию использует SimpleCacheConfiguration, который представляет собой кеш, реализованный с помощью ConcurrentMapCacheManager.

CacheManager: менеджер кеша, управляет различными компонентами кеша.

CacheManager описывать
SimpleCacheManager Используйте коллекцию контрольных точек для хранения кеша, в основном для тестирования
ConcurrentMapCacheManager Используйте ConcurrentMap для хранения кеша
NoOpCacheManager Только для тестирования, на самом деле не будет хранить кеш
EhCacheCacheManager Использование EhCache в качестве технологии кэширования
GuavaCacheManager Использование Guava в качестве технологии кэширования
HazelcastCacheManager Использование Hazelcast в качестве технологии кэширования
JCacheCacheManager Поддерживает реализацию стандарта JCache (JSR-107) в качестве технологии кэширования.
RedisCacheManager Использование Redis в качестве технологии кэширования

Кэшировать детали аннотаций

  • @CacheConfig: в основном используется для настройки некоторых общих конфигураций кэша, которые будут использоваться в этом классе.
    Здесь @CacheConfig(cacheNames = "users"): содержимое, возвращаемое в объекте доступа к данным, настроено для хранения в объекте кеша с именем users. Мы также можем настроить набор кеша напрямую через @Cacheable без использования этой аннотации. имя для определения .

  • @Cacheable: в основном для настройки метода результат может быть кэширован в соответствии с параметрами запроса метода. При этом при запросе он сначала будет получен из кеша, а если его нет, то будет инициирован доступ к БД. Аннотация в основном имеет следующие параметры:

    • значение, cacheNames: Два эквивалентных параметра (cacheNames являются новыми в Spring 4, как псевдоним для значения), которые используются для указания имени коллекции кэш-хранилища. Из-за добавления @CacheConfig в Spring 4 атрибут value, который изначально требовался в Spring 3, также стал несущественным элементом.

    • key: значение ключа объекта кэша, хранящегося в коллекции Map, не требуется.По умолчанию в качестве значения ключа используются все комбинации параметров функции.Если вы настраиваете его самостоятельно, вам нужно использовать выражение SpEL, такое as: @Cacheable(key = "#p0"): use Первый параметр функции используется как кэшированное значение ключа. Подробнее о выражениях SpEL см. в официальной документации.

    • condition: Условие кэшируемого объекта, не требуется, также необходимо использовать выражение SpEL, кэшироваться будет только контент, удовлетворяющий условию выражения, например: @Cacheable(key = "#p0", condition = "#p0.length ()

    • unless: еще один параметр условия кэша, необязательный, для него необходимо использовать выражение SpEL. Разница между ним и параметром условия заключается в его времени оценки.Условие оценивается после вызова функции, поэтому о нем можно судить по результату.

    • keyGenerator: используется для указания генератора ключей, не требуется. Чтобы указать собственный генератор ключей, нам нужно реализоватьorg.springframework.cache.interceptor.KeyGeneratorинтерфейс и используйте этот параметр для указания. Следует отметить, что этот параметр и ключ являются взаимоисключающими.

    • cacheManager: используется для указания используемого менеджера кеша, не требуется. Нужно использовать только в том случае, если их несколько.

    • cacheResolver: используется для указания используемого преобразователя кэша, не требуется. нужно пройтиorg.springframework.cache.interceptor.CacheResolverinterface для реализации собственного преобразователя кэша и укажите его с помощью этого параметра.

  • @CachePut: Настроен на метод, может кэшироваться по условиям, заданным параметрами.Отличается от @Cacheable тем, что не проверяет, есть ли в кэше ранее выполненный результат, а каждый раз выполняет метод и выполняет Результаты сохраняются в кэше в виде пар ключ-значение, поэтому в основном используются для операций добавления и модификации данных. Его параметры аналогичны @Cacheable.Для конкретных функций см. анализ параметров @Cacheable выше.

  • @CacheEvict: настроен на функцию, обычно используемую в методе удаления, для удаления соответствующих данных из кэша. В дополнение к тем же параметрам, что и @Cacheable, он имеет следующие два параметра:

    • allEntries: не требуется, по умолчанию false. При значении true все данные будут удалены.

    • beforeInvocation: не требуется, по умолчанию false, данные будут удалены после вызова метода, если true, данные будут удалены до вызова метода.

Собрать кеш Spring Boot по умолчанию

Включить поддержку кеша

добавить в класс запуска@EnableCachingВключите поддержку кэша для автоматического сканирования.

@SpringBootApplication
@EnableCaching  // 开启缓存功能
public class CacheApplication {

	public static void main(String[] args) {
		SpringApplication.run(CacheApplication.class, args);
	}
}

Добавить зависимость spring-boot-starter-cache

Добавьте зависимость spring-boot-starter-cache в pom.xml.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

Подготовить данные

Макет данных базы данных

/**
 * 数据工厂,模拟数据库的数据
 *
 * @author star
 **/
public class DataFactory {

    private DataFactory() {
    }

    private static List<UserDto> userDtoList;

    static {
        // 初始化集合
        userDtoList = new ArrayList<>();

        UserDto user = null;
        for (int i = 0; i < 10; i++) {
            user = new UserDto();
            user.setName("star" + i);
            user.setAge("2" + i);
            userDtoList.add(user);
        }
    }

    public static List<UserDto> getUserDaoList() {
        return userDtoList;
    }
}

Написать бизнес-код кеша

  • Напишите слой DAO
/**
 * UserRepository
 *
 * @author star
 **/
@Repository
public class UserRepository {

    /**
     * 获取用户信息(此处是模拟的数据)
     */
    public UserDto getUser(String username) {
        UserDto user = getUserFromList(username);
        return user;
    }

    /**
     * 删除用户信息
     */
    public List<UserDto> deleteUser(String username) {

        List<UserDto> userDaoList = DataFactory.getUserDaoList();
        userDaoList.remove(getUserFromList(username));

        return userDaoList;
    }

    /**
     * 新增数据
     */
    public List<UserDto> save(String username) {
        // 添加到集合
        List<UserDto> userDaoList = DataFactory.getUserDaoList();
        for (UserDto userDto : userDaoList) {
            // 不能重复添加相同数据
            if (Objects.equals(userDto.getName(), username)) {
                return userDaoList;
            }
        }
        UserDto user = new UserDto();
        user.setName(username);
        user.setAge("50");
        userDaoList.add(user);

        return userDaoList;
    }

    /**
     * 从模拟的数据集合中筛选 username 的数据
     */
    private UserDto getUserFromList(String username) {

        List<UserDto> userDaoList = DataFactory.getUserDaoList();
        for (UserDto user : userDaoList) {
            if (Objects.equals(user.getName(), username)) {
                return user;
            }
        }
        return null;
    }
}
  • Напишите сервисный слой
/**
 * UserService
 *
 * @author star
 **/
@Service
@CacheConfig(cacheNames = "users")// 指定缓存名称,在本类中是全局的
public class UserService {

    @Autowired
    private UserRepository userRepository;

    /**
     * 缓存 key 是 username 的数据到缓存 users 中,
     * 如果没有指定 key,则方法参数作为 key 保存到缓存中
     */
    @Cacheable(key = "#username")
    public UserDto getUser(String username) {
        System.out.println("从数据库中获取数据,而不是读取缓存");
        return userRepository.getUser(username);
    }


    /**
     * 新增或更新缓存中的数据
     */
    @CachePut(key = "#username")
    public List<UserDto> save(String username) {
        return userRepository.save(username);
    }

    /**
     * 从缓存 users 中删除 key 是 username 的数据
     */
    @CacheEvict(key = "#username")
    public List<UserDto> deleteUser(String username) {
        System.out.println("从数据库中删除数据,以及缓存中的数据");
        return userRepository.deleteUser(username);
    }
}
  • Напишите слой контроллера
/**
 * CacheResource
 *
 * @author star
 **/
@RestController
@RequestMapping("/api")
public class CacheResource {

    @Autowired
    private UserService userService;

    @GetMapping("/users/{username}")
    public ResponseEntity<UserDto> getUser(@PathVariable String username) {
        // 获取数据
        UserDto user = userService.getUser(username);
        return ResponseEntity.ok(user);
    }

    @PutMapping("/users/{username}")
    public ResponseEntity<List<UserDto>> save(@PathVariable String username) {
        List<UserDto> userDtoList = userService.save(username);

        return ResponseEntity.ok(userDtoList);
    }

    @DeleteMapping("/users/{username}")
    public ResponseEntity<List<UserDto>> delete(@PathVariable String username) {
        List<UserDto> userDtoList = userService.deleteUser(username);

        return ResponseEntity.ok(userDtoList);
    }
}

демо

через интерфейс несколько разhttp://localhost:8080/api/users/star1ПОЛУЧИТЬ данные для наблюдения за эффектом:

get

Вы можете видеть, что кеш включен, и его эффекты следующие:

result