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.
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++;
}
}
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.
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
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>
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.
Serait vraiment utile si quelqu'un peut indiquer ce qui me manque.