Multi cache managers

Добрый день.

jmix: 2.3.2
plugin: 2.3.2-241
idea: IntelliJ IDEA 2024.1.4 (Community Edition)

Занимаюсь миграцией кубинского приложения на jmix и столкнулся с проблемой наличия нескольких менеджеров кэша. То есть в приложении есть конфигурация, которая определяет несколько менеджеров кешей (caffeine) под определенные задачи. После переноса этой конфигурации в jmix приложении при старте приложения получаю в логах следующую ошибку:

Parameter 0 of constructor in io.jmix.security.impl.role.ResourceRoleRepositoryImpl required a single bean, but 2 were found:

  • some_name_one: defined by method ‘getOneCacheManager’ in class path resource [SomeCacheConfiguration.class]
  • some_name_two: defined by method ‘getTwoCacheManager’ in class path resource [SomeCacheConfiguration.class]
    This may be due to missing parameter name information
    Action:
    Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed

Если я правильно понимаю, в случае если я помечу один из выше указанных менеджеров кэша как @Primary, то он будет использоваться для кеширования ResourceRoleRepositoryImpl (и не только) чего бы не хотелось совсем.

Подскажите пжлст как в jmix использовать несколько менеджеров кэша (и разных типов).

Спасибо.

Добрый день.

Jmix-бины, использующие CacheManager ожидают его в “единственном” экземпляре.
И при наличии нескольких CacheManager’ов необходимо указать @Primary, который будет использован везде, где не указан qualifier.

Можете рассказать подробнее о вашем сценарии использования?

На данный момент возможны следующие варианты:

  • Если вы используете множественные CacheManager’ы только в рамках своего проектного кода (а framework-часть не требует такого разделения), то можно добавить @Primary на один из CM - он будет использоваться в Jmix-бинах и в целом по-умолчанию, а в рамках ваших проектных бинов, требующих других CM’ов указывать их @Qualifier.
  • Если вам нужно, чтобы различные Jmix-бины использовали разные CM, то как вариант выглядит возможным переопределение на стороне проекта тех Jmix-бинов, которым нужны специфические CM и добавление в них соответствующих @Qualifier. И указание @Primary CM, как и в предыдущем варианте.

С уважением,
Иван

Добрый день.

Сценарий использования следующий:
Есть набор объектов, который “модифицируется” на основе ролей связанных с пользователем перед тем как их отдать (в виде json) пользователю. “Модификация” занимает значительное время поэтому результат “модификации” кэшируется (чтобы при следующем обращении сразу же отдавать пользователю готовый вариант, кэш может быть сброшен при определенных событиях и запрашиваемые объекты будут заново “модифицироваться”).

Если я помечаю создаваемый мною CacheManager @Primary:

@Primary
@Bean("some_name_one")
public CacheManager getOneCacheManager() {
    CaffeineCacheManager cacheManager = new CaffeineCacheManager("some_name_one");
    cacheManager.setCaffeine(Caffeine.newBuilder()
        .expireAfterWrite(12, TimeUnit.HOURS)
        .expireAfterAccess(1, TimeUnit.HOURS));
    return cacheManager;
}

, то при старте приложения получаю следующую ошибку:

...
Caused by: java.lang.IllegalStateException: Unable to find cache: resource-roles-cache
...

, которая выбрасывается в ResourceRoleRepositoryImpl:

    @PostConstruct
    public void init() {
        rolesCache = cacheManager.getCache(RESOURCE_ROLES_CACHE_NAME);
        if (rolesCache == null) {
            throw new IllegalStateException(String.format("Unable to find cache: %s", RESOURCE_ROLES_CACHE_NAME));
        }
    }

Вот с этим не могу справиться.

То чего хочется получить в результате это “отделить мух от котлет” и не лезть со своим кэшем в кэш платформы.

Буду очень признателен если сможете указать как это сделать (и можно ли это сделать).

Спасибо.

С уважением, Алексей.

Добрый день.

Конкретно эта ошибка возникает из-за того, что при создании на уровне проекта своего CacheManager отключается конфигурация org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration, которая (через JCacheManagerCustomizer) создавала конкретные Jmix-кэши.

Соответственно, ResourceRoleRepositoryImpl не находит свой кэш, т.к. его никто не создал.

Создание нескольких CacheManager’ов выглядит несколько проблематично.

А насколько вам принципиален отдельный CacheManager? Рассматривался ли вариант создания кэша для ваших данных, используя существующий CM?

Если же вам нужен именно Caffeine, то при добавлении зависимости (но без явного создания проектного CM-бина) Spring автоматически сконфигурит CM, используя Caffeine имплементацию.
В итоге все кэши станут Caffeine. А вы также создаете отдельный кэш под свои нужны.

С уважением,
Иван

1 симпатия

Добрый день.

Спасибо за развернутый ответ.

В целом некритично использовать кэш платформы. Про caffeine понял. Буду так использовать.

С уважением, Алексей.

Сделал так, вроде работает.

@Configuration(CacheConfiguration.NAME)
public class CacheConfiguration {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    public static final String NAME = "app_cacheConfiguration";

    @Bean
    @SuppressWarnings({"rawtypes", "unchecked"})
    JCacheManagerCustomizer someCache() {
        return cacheManager -> {
            Cache<Object, Object> cache = cacheManager.getCache("CACHE_NAME");
            if (cache == null) {
                MutableConfiguration configuration = new MutableConfiguration();
                cacheManager.createCache("CACHE_NAME", configuration);
            }
        };
    }
}

Спасибо.