web-dev-qa-db-fra.com

Spring Framework 5 et EhCache 3.5

J'ai essayé d'utiliser les fonctionnalités de mise en cache EhCache 3.5 dans notre application Web basée sur Spring Boot 2/Spring Framework 5.

J'ai ajouté la dépendance EHCache:

    <dependency>
        <groupId>org.ehcache</groupId>
        <artifactId>ehcache</artifactId>
        <version>3.5.0</version>
    </dependency>
    <dependency>
        <groupId>javax.cache</groupId>
        <artifactId>cache-api</artifactId>
        <version>1.0.0</version>
    </dependency>

Ensuite, créez le fichier ehcache.xml dans le dossier src/main/resources:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"
    monitoring="autodetect" dynamicConfig="true">

    <cache name="orders" maxElementsInMemory="100" 
        eternal="false" overflowToDisk="false" 
        memoryStoreEvictionPolicy="LFU" copyOnRead="true"
        copyOnWrite="true" />
</ehcache>

Le guide de référence de Spring 5 ne mentionne pas l'utilisation d'EHCache. Le guide de référence de Spring 4 indique: "Ehcache 3.x est entièrement conforme à JSR-107 et aucun support dédié n'est requis pour cela."

J'ai donc créé le contrôleur OrderController et le noeud final REST:

@Cacheable("orders")
@GetMapping(path = "/{id}")
public Order findById(@PathVariable int id) {
    return orderRepository.findById(id);
}

Configuration de démarrage du printemps:

@SpringBootApplication
@EnableCaching
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Mais lorsque j'appelle ce noeud final, je reçois une exception:

Impossible de trouver le cache nommé 'ordres' pour Builder [org.Order org.OrderController.findById (int)] caches = [orders] | clé = '' | keyGenerator = '' | cacheManager = '' | cacheResolver = '' | condition = '' | à moins que = '' | sync = 'false'

Ensuite, j'ai essayé d'utiliser l'exemple de Spring Framework 4:

@Bean
public CacheManager cacheManager() {
    return new EhCacheCacheManager(ehCacheCacheManager().getObject());
}

@Bean
public EhCacheManagerFactoryBean ehCacheCacheManager() {
    EhCacheManagerFactoryBean cmfb = new EhCacheManagerFactoryBean();
    cmfb.setConfigLocation(new ClassPathResource("ehcache.xml"));
    cmfb.setShared(true);
    return cmfb;
}

Mais il ne compile pas à cause d'une exception:

Le type net.sf.ehcache.CacheManager ne peut pas être résolu. Il est indirectement référencé à partir du fichier .class requis

S'il vous plaît donnez votre avis.

3
Sergey

Il y a un mélange de choses ici. Ehcache 3, que vous utilisez, est utilisé avec Spring via JCache.

C'est pourquoi vous devez utiliser spring.cache.jcache.config=classpath:ehcache.xml.

Ensuite, votre configuration Ehcache est bien une configuration Ehcache 2. Alors est la EhCacheCacheManager. Pour JCache, vous devriez utiliser JCacheCacheManager. Mais en fait, vous n'en avez même pas besoin avec un ehcache.xml.

Voici les étapes pour le faire fonctionner

Étape 1: Définissez les dépendances correctes. Notez qu'il n'est pas nécessaire de spécifier une version telle qu'elle est fournie par la gestion des dépendances de pom parent. javax.cache est maintenant la version 1.1.

<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
</dependency>
<dependency>
    <groupId>javax.cache</groupId>
    <artifactId>cache-api</artifactId>
</dependency>

Étape 2: Ajoutez un fichier ehcache.xml dans src/main/resources. Un exemple ci-dessous.

<?xml version="1.0" encoding="UTF-8"?>
<config
    xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
    xmlns:jsr107='http://www.ehcache.org/v3/jsr107'
    xmlns='http://www.ehcache.org/v3'
    xsi:schemaLocation="
        http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.5.xsd
        http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.5.xsd">

  <service>
    <jsr107:defaults enable-management="false" enable-statistics="true"/>
  </service>

  <cache alias="value">
    <resources>
      <heap unit="entries">2000</heap>
    </resources>
  </cache>
</config>

Étape 3: Un application.properties avec cette ligne est nécessaire pour trouver le ehcache.xml

spring.cache.jcache.config=classpath:ehcache.xml

Notez que puisque JCache est trouvé dans le chemin de classe, Spring Cache le choisira comme fournisseur de cache. Il n'est donc pas nécessaire de spécifier spring.cache.type=jcache.

Étape 4: Activez la mise en cache comme vous l'avez fait

    @SpringBootApplication
    @EnableCaching
    public class Cache5Application {

        private int value = 0;

        public static void main(String[] args) {
            ApplicationContext context = SpringApplication.run(Cache5Application.class, args);
            Cache5Application app = context.getBean(Cache5Application.class);
            System.out.println(app.value());
            System.out.println(app.value());
        }

        @Cacheable("value")
        public int value() {
            return value++;
        }
    }
4
Henri

Vous devez le forcer à utiliser ehcache version 2

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>2.10.3</version>
</dependency>

Pour utiliser ehcache 3:

Voici l'application:

@SpringBootApplication
@EnableCaching
public class Application {

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

Voici l'application.yml

spring:
  cache:
    ehcache:
      config: ehcache.xml

Voici un service avec un compteur pour tester

@Service
public class OrderService {

    public static int counter=0;

    @Cacheable("orders")
    public Order findById(Long id) {
        counter++;
        return new Order(id, "desc_" + id);
    }
}

Voici un test pour prouver qu'il utilise le cache:

@RunWith(SpringRunner.class)
@SpringBootTest
public class OrderServiceTest {

    @Autowired
    private OrderService orderService;

    @Test
    public void getHello() throws Exception {
        orderService.findById(1l);
        assertEquals(1, OrderService.counter);
        orderService.findById(1l);
        assertEquals(1, OrderService.counter);
        orderService.findById(2l);
        assertEquals(2, OrderService.counter);
    }
}

Voir ici pour un exemple de travail.

2
Essex Boy

J'ai fait des recherches supplémentaires. La configuration suivante n'est pas sélectionnée par Spring Boot (à partir de application.properties):

spring.cache.ehcache.config=classpath:ehcache.xml

J'ai donc créé jcache.xml et également placé dans le dossier src/main/resource:

<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
    xmlns='http://www.ehcache.org/v3'
    xsi:schemaLocation="
        http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd">

    <cache alias="orders">
        <key-type>org.springframework.cache.interceptor.SimpleKey</key-type>
        <value-type>Java.util.Collections$SingletonList</value-type>
        <heap unit="entries">200</heap>
    </cache>
</config>

Ensuite, j'ai modifié les paramètres dans application.properties en

spring.cache.jcache.config=classpath:jcache.xml

Spring Caching fonctionne maintenant correctement. Cependant, il reste à savoir comment récupérer ehcache.xml

0
Sergey

hmm .. changer ehcache.xml en, a fait le tour ..

<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
    xmlns='http://www.ehcache.org/v3'
    xmlns:jsr107='http://www.ehcache.org/v3/jsr107'
    xsi:schemaLocation="
        http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd
        http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd">

    <service>
        <jsr107:defaults enable-management="true"
            enable-statistics="true" />
    </service>

    <cache alias="vehicles" uses-template="heap-cache" />

    <cache-template name="heap-cache">
        <heap unit="entries">20</heap>
    </cache-template>
</config>
0
Sandy

Face au même problème. 

  • Mon ehcache.xml ressemble à

    <config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
        xmlns='http://www.ehcache.org/v3'
        xmlns:jsr107='http://www.ehcache.org/v3/jsr107'
        xsi:schemaLocation="
            http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd
            http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd">
      <service>
          <jsr107:defaults>
              <jsr107:cache name="vehicles" template="heap-cache" />
          </jsr107:defaults>
      </service>
      <cache-template name="heap-cache">
          <heap unit="entries">20</heap>
      </cache-template>
    </config>
    
  • Avoir configuré spring.cache.jcache.config=classpath:ehcache.xml dans application.properties

  • Avoir @EnableCaching sur ma classe d'application.

  • Avoir @CacheResult sur la mise en œuvre de mon service.

@CacheResult (cacheName = "véhicules") public VehicleDetail GetVehicle (@CacheKey String vehicleId) lève une exception VehicleServiceException.

  • FAITES NOTE que je n’ai pas de bean CacheManager.

Serait vraiment utile si quelqu'un peut indiquer ce qui me manque.

0
Sandy