Вызов метода Spring Cacheable в исключении приведения класса метода Cacheable

Я пытаюсь использовать Spring Cacheable, но получаю исключение приведения класса

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CacheableTest.class, loader = AnnotationConfigContextLoader.class)
@Configuration
@EnableCaching
public class CacheableTest {
    public static final String CACHE = "cache";

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

    @Autowired
    DataService service;

    @Test
    public void cacheTest() {
        final String name = "name";
        Data a = service.getData(name);
        Data b = service.getData(new String(name));
        Assert.assertSame(a, b);
        String c = service.getValue(service.getData(name));
        String d = service.getValue(service.getData(new String(name)));
        Assert.assertSame(c, d);
        String e = service.getValue(name);
        String f = service.getValue(new String(name));
        Assert.assertSame(e, f);
    }

    public static class Data {
        private String value;
        public Data(String value) {
            this.value = value;
        }
    }

    @Service
    public static class DataService {
        @Resource
        private DataService self;

        @Cacheable(CACHE)
        public Data getData(String name) {
            return new Data(name);
        }

        @Cacheable(CACHE)
        public String getValue(Data data) {
            return data.value;
        }

        @Cacheable(CACHE)
        public String getValue(String name) {
            return self.getData(name).value;
        }
    }

}

Исключением является CacheableTest$Data cannot be cast to java.lang.String, который происходит в строке String e. Мы знаем почему?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
0
741
1

Ответы 1

Вы объявили 2 метода с одинаковыми параметрами, но с другим возвращаемым типом .:

public Data getData(String name)
public String getValue(String name) 

И вы пометили их обоих как @Cacheable с тем же именем кеша CACHE. В результате вы используете один кеш для хранения результатов обоих методов. Оба метода имеют точно такие же параметры (String), поэтому ключи кеша, рассчитанные Spring для Data и Value, будут конфликтовать.

Первый вызываемый метод вернет результат, который spring поместит в кеш, а второй попытается получить тот же результат из кеша (потому что имя кеша и параметр метода совпадают) и попытается преобразовать его в другой тип - следовательно, , исключение приведения класса.

Это почти то же самое, как если бы вы сделали это:

Map<String, Object> cache = new HashMap<>();
cache.put("key", "value1");
int i = (Integer)cache.get("key")

Ах хорошо. Таким образом, @Cacheable по умолчанию проверяет только входные параметры, чтобы найти кэшированный результат. Спасибо, что ответили на вопрос "почему". Вы знаете, как решить эту проблему (например, заставить @Cacheable объединить тип возвращаемого значения + имя метода + входные параметры в качестве уникального ключа для поиска кеша)?

user1589188 23.07.2019 03:27

Я думаю, что решение - просто использовать отдельные кеши для разных типов. Например. вы можете назвать один кэш "dataCache", другой - "valueCache". Я не могу придумать какой-либо веской причины хранить оба типа объектов в одном кеше. По крайней мере, я исправил это так, и у меня это сработало. Вы также можете создать собственный генератор ключей, но этого не сделали.

maraswrona 24.07.2019 12:08

Честно говоря, мой ответ выше - это всего лишь лучшее предположение о том, что происходит. Я столкнулся с той же проблемой, поэтому нашел этот вопрос. Мне не удалось найти подробную весеннюю документацию о том, как @Cacheable работает по этой конкретной теме. Если кто-то может указать мне на это, я буду рад дать ссылку на него в своем ответе и при необходимости отредактировать его.

maraswrona 24.07.2019 12:09

Другие вопросы по теме