-
Notifications
You must be signed in to change notification settings - Fork 18
/
feed.xml
1862 lines (1729 loc) · 96.2 KB
/
feed.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
<title type="text">Ehcache</title>
<generator uri="https://github.com/jekyll/jekyll">Jekyll</generator>
<link rel="self" type="application/atom+xml" href="https://www.ehcache.org/feed.xml" />
<link rel="alternate" type="text/html" href="https://www.ehcache.org" />
<updated>2024-10-22T15:08:36+00:00</updated>
<id>https://www.ehcache.org/</id>
<author>
<name>Ehcache</name>
<uri>https://www.ehcache.org/</uri>
<email>[email protected]</email>
</author>
<entry>
<title type="html"><![CDATA[Prevent spontaneous cache creation]]></title>
<link rel="alternate" type="text/html" href="https://www.ehcache.org/blog/2017/03/15/spontaneous-cache-creation.html" />
<id>https://www.ehcache.org/blog/2017/03/15/spontaneous-cache-creation</id>
<published>2017-03-15T16:00:00+00:00</published>
<updated>2017-03-15T16:00:00+00:00</updated>
<author>
<name>Henri Tremblay</name>
<uri>https://www.ehcache.org</uri>
</author>
<content type="html"><div class="paragraph">
<p>I played a lot with JCache connectors lately. To plug <a href="http://www.ehcache.org">Ehcache 3</a> to different things.</p>
</div>
<div class="paragraph">
<p>I noticed one really dangerous thing. Frameworks tend to spontaneously create caches that were not explicitly defined. I
think it is coming from the JCache spirit that there should be a default cache configuration. It is nonetheless a bad idea.</p>
</div>
<div class="paragraph">
<p>Let&#8217;s look at two examples</p>
</div>
<div class="sect1">
<h2 id="spring"><a class="anchor" href="#spring"></a>Spring</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Caching in Spring is implemented by <code>spring-cache</code>. To plug JCache to <code>spring-cache</code> you use the <code>JCacheCacheManager</code>. By default
when a cache isn&#8217;t available in the <code>CacheManager</code>, Spring calls <code>JCacheCacheManager.getMissingCache</code>. So far so good.</p>
</div>
<div class="paragraph">
<p>The default implementation for this method returns <code>null</code> when a cache doesn&#8217;t exist. This <code>null</code> will then be handled at
higher levels to throw a nice exception.</p>
</div>
<div class="paragraph">
<p>If you want to explicitly support spontaneous cache creation, <code>getMissingCache</code> is where you should put your creation code.</p>
</div>
<div class="paragraph">
<p>However, watch out if you do that. You might lose track of all the existing caches. And please, <strong>never</strong> do the following.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Override
protected Cache getMissingCache(String name) {
Cache cache = super.getMissingCache(name);
if(cache == null) {
return new JCacheCache(cacheManager.createCache(name, new MutableConfiguration&lt;&gt;()));
}
return cache;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>It returns a cache configured using default. It is <strong>never</strong> what you want. I will repeat that because you might think I don&#8217;t
mean it. You might think defaults are cool. <strong>It is never what you want</strong>.</p>
</div>
<div class="paragraph">
<p>Then, as usual, Spring tries to be nice with us. So if you enable caching (<code>@EnableCaching</code>), that the JSR-107 API is in
the classpath and that you do not expose any <code>CacheManager</code>, Spring will create one for you.</p>
</div>
<div class="paragraph">
<p>The <code>JCacheCacheConfiguration</code> will get a default JSR-107 <code>CacheManager</code> and add a list of caches taken from the cache property
<code>spring.cache.cache-names</code>. These caches are by default created using a <code>new MutableConfiguration&lt;&gt;()</code>. As we said above, this
is not a correctly configured cache.</p>
</div>
<div class="paragraph">
<p>The solution is to expose the wanted cache configuration in a bean.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Bean
public javax.cache.configuration.Configuration&lt;Object, Object&gt; cacheConfiguration() {
CacheConfiguration&lt;Object, Object&gt; cacheConfiguration = CacheConfigurationBuilder
.newCacheConfigurationBuilder(Object.class, Object.class, ResourcePoolsBuilder
.newResourcePoolsBuilder().heap(100))
.build();
javax.cache.configuration.Configuration&lt;Object, Object&gt; configuration =
Eh107Configuration.fromEhcacheCacheConfiguration(cacheConfiguration);
return configuration;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This bean will be magically used as cache default. You should always do this and never let <code>`new MutableConfiguration&lt;&gt;()</code>
be used.</p>
</div>
<div class="paragraph">
<p>An alternative (preferred in fact, thanks <a href="https://twitter.com/snicoll">Stéphane Nicoll</a> for the tip), it to use a <code>JCacheManagerCustomizer</code> instead
of the <code>spring.cache.cache-names</code> property. Like this:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Bean
public JCacheManagerCustomizer cacheManagerCustomizer() {
return cm -&gt; {
Configuration&lt;Object, Object&gt; cacheConfiguration = createCacheConfiguration();
cm.createCache("vets", cacheConfiguration);
};
}
private Configuration&lt;Object, Object&gt; createCacheConfiguration() {
return Eh107Configuration.fromEhcacheCacheConfiguration(CacheConfigurationBuilder
.newCacheConfigurationBuilder(Object.class, Object.class, ResourcePoolsBuilder
.newResourcePoolsBuilder().heap(100)));
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="hibernate"><a class="anchor" href="#hibernate"></a>Hibernate</h2>
<div class="sectionbody">
<div class="paragraph">
<p>To use JCache with Hibernate we need to use the <code>JCacheRegionFactory</code>. The problem with <code>JCacheRegionFactory</code> is that by
default if a cache is not found, it will spontaneously create a cache by passing <code>new MutableConfiguration()</code>. This means
that instead of using a properly configured cache, you end up with some random default configuration (infinite on heap for
Ehcache).</p>
</div>
<div class="paragraph">
<p>This is really bad because it is pretty hard to detect.</p>
</div>
<div class="paragraph">
<p>What I recommend in this case is, again, to override the default. In the latest Hibernate versions (5.2.8+) (thanks to
<a href="https://github.com/hibernate/hibernate-orm/pull/1783">HHH-1783</a>, we can do the following</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Override
protected Cache&lt;Object, Object&gt; createCache(String regionName, Properties properties, CacheDataDescription metadata) {
throw new IllegalArgumentException("Unknown hibernate cache: " + regionName);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>In older versions, sadly, there is no straightforward cache creation method to override. The best we have is
<code>newDefaultConfig</code> which provides the default configuration. One sad thing is that you don&#8217;t have the actual cache name
here. You will need to debug to know it.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Override
protected Configuration&lt;Object, Object&gt; newDefaultConfig(Properties properties, CacheDataDescription metadata) {
throw new IllegalArgumentException("Unknown hibernate cache: " + metadata);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Again, an alternative solution would be to provide a meaningful default cache configuration in this method.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="conclusion"><a class="anchor" href="#conclusion"></a>Conclusion</h2>
<div class="sectionbody">
<div class="paragraph">
<p>I do understand that frameworks do not like to fail with exceptions. This helps the feeling that they are working out of
the box.</p>
</div>
<div class="paragraph">
<p>But I still think silently not caching or providing random default configuration is dangerous. Using my two workarounds
should prevent a lot of headaches.</p>
</div>
</div>
</div>
<p><a href="https://www.ehcache.org/blog/2017/03/15/spontaneous-cache-creation.html">Prevent spontaneous cache creation</a> was originally published by Henri Tremblay at <a href="https://www.ehcache.org">Ehcache</a> on March 15, 2017.</p></content>
</entry>
<entry>
<title type="html"><![CDATA[Ehcache out of his Element]]></title>
<link rel="alternate" type="text/html" href="https://www.ehcache.org/resources/2016/06/23/ehcache-out-element.html" />
<id>https://www.ehcache.org/resources/2016/06/23/ehcache-out-element</id>
<published>2016-06-23T00:00:00+00:00</published>
<updated>2016-06-23T00:00:00+00:00</updated>
<author>
<name></name>
<uri>https://www.ehcache.org</uri>
</author>
<content type="html"><div class="ulist">
<ul>
<li>
<p>Conference page: <a href="http://cfp.devoxx.pl/2016/talk/DIW-5033/Ehcache%20out%20of%20his%20Element" class="bare">http://cfp.devoxx.pl/2016/talk/DIW-5033/Ehcache%20out%20of%20his%20Element</a></p>
</li>
<li>
<p>Video: <a href="https://www.youtube.com/watch?v=RSpgLZ1U75g" class="bare">https://www.youtube.com/watch?v=RSpgLZ1U75g</a></p>
</li>
</ul>
</div>
<p><a href="https://www.ehcache.org/resources/2016/06/23/ehcache-out-element.html">Ehcache out of his Element</a> was originally published by at <a href="https://www.ehcache.org">Ehcache</a> on June 23, 2016.</p></content>
</entry>
<entry>
<title type="html"><![CDATA[Caching 101: Caching on the JVM (and beyond)]]></title>
<link rel="alternate" type="text/html" href="https://www.ehcache.org/resources/2016/06/10/caching-101.html" />
<id>https://www.ehcache.org/resources/2016/06/10/caching-101</id>
<published>2016-06-10T00:00:00+00:00</published>
<updated>2016-06-10T00:00:00+00:00</updated>
<author>
<name></name>
<uri>https://www.ehcache.org</uri>
</author>
<content type="html"><div class="paragraph">
<p>This session, while similar to the previous one with the same title, has been improved based on feedback and experience.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Conference page: <a href="https://cfp.devoxx.co.uk/2016/talk/FWR-0829/Caching_101:_Caching_on_the_JVM_(and_beyond" class="bare">https://cfp.devoxx.co.uk/2016/talk/FWR-0829/Caching_101:_Caching_on_the_JVM_(and_beyond</a>)</p>
</li>
<li>
<p>Video: <a href="https://www.youtube.com/watch?v=FQfd8x29Ud8" class="bare">https://www.youtube.com/watch?v=FQfd8x29Ud8</a></p>
</li>
</ul>
</div>
<p><a href="https://www.ehcache.org/resources/2016/06/10/caching-101.html">Caching 101: Caching on the JVM (and beyond)</a> was originally published by at <a href="https://www.ehcache.org">Ehcache</a> on June 10, 2016.</p></content>
</entry>
<entry>
<title type="html"><![CDATA[Ehcache 3, JSR-107 and Spring 4.2]]></title>
<link rel="alternate" type="text/html" href="https://www.ehcache.org/blog/2016/05/18/ehcache3_jsr107_spring.html" />
<id>https://www.ehcache.org/blog/2016/05/18/ehcache3_jsr107_spring</id>
<published>2016-05-18T05:30:00+00:00</published>
<updated>2016-05-18T05:30:00+00:00</updated>
<author>
<name>Geoff Gibson</name>
<uri>https://www.ehcache.org</uri>
</author>
<content type="html"><div class="paragraph">
<p>In this post I would like to demonstrate how to use <a href="https://github.com/ehcache/ehcache3">Ehcache 3.0</a> as Spring&#8217;s caching implementation.
This article will show you how to use <a href="https://github.com/ehcache/ehcache3">Ehcache 3.0</a>, <a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/">Spring 4.2</a> and the <a href="https://jcp.org/en/jsr/detail?id=107">JSR-107</a> annotations to build a simple Spring web application.
I have also included some background reading for those of you that would like to read more in depth on the subject matter.</p>
</div>
<div class="sect1">
<h2 id="background-reading"><a class="anchor" href="#background-reading"></a>Background reading</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Ehcache 3.0 Documentation</p>
<div class="ulist">
<ul>
<li>
<p><a href="http://www.ehcache.org/documentation/3.0/" class="bare">http://www.ehcache.org/documentation/3.0/</a></p>
</li>
</ul>
</div>
</li>
<li>
<p>Spring Cache Abstraction</p>
<div class="ulist">
<ul>
<li>
<p><a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html" class="bare">http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html</a></p>
</li>
</ul>
</div>
</li>
<li>
<p>Spring Cache Abstraction, JCache (JSR-107) annotations</p>
<div class="ulist">
<ul>
<li>
<p><a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html#cache-jsr-107" class="bare">http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html#cache-jsr-107</a></p>
</li>
<li>
<p><a href="https://spring.io/blog/2014/04/14/cache-abstraction-jcache-jsr-107-annotations-support" class="bare">https://spring.io/blog/2014/04/14/cache-abstraction-jcache-jsr-107-annotations-support</a></p>
</li>
</ul>
</div>
</li>
<li>
<p>The following is the GitHub example associated with this post:</p>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/gibsong/ehcache-jsr107-spring" class="bare">https://github.com/gibsong/ehcache-jsr107-spring</a></p>
</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="jsr-107jcache-annotations"><a class="anchor" href="#jsr-107jcache-annotations"></a>JSR-107(JCache) Annotations</h2>
<div class="sectionbody">
<div class="paragraph">
<p>If you are familiar with Spring, you know that it provides annotations to assist in developing applications.
In regards to caching, Spring offers support for two sets of annotations that can be used to implement caching.
You have the original Spring annotations and the new JSR-107 annotations.
The original Spring annotations are available to use with Spring versions 3.1+, while the JSR-107 annotations are only available in Spring 4.1+.
In this example we are going to use the JSR-107 annotations.
Below I have listed the most commonly used JSR-107(JCache) annotations, with brief descriptions as well as links to their API&#8217;s.</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>@CacheDefaults</strong> - allows configuration of defaults at the class level.
For instance, you can define a cache name at the class level and this will be used as the default.</p>
<div class="ulist">
<ul>
<li>
<p><a href="http://static.javadoc.io/javax.cache/cache-api/1.0.0/javax/cache/annotation/CacheDefaults.html" class="bare">http://static.javadoc.io/javax.cache/cache-api/1.0.0/javax/cache/annotation/CacheDefaults.html</a></p>
</li>
</ul>
</div>
</li>
<li>
<p><strong>@CacheResult</strong> - Cache the return value of the method.
The first time the method is invoked with a particular key it will be run and the value will be cached.
On subsequent calls with the same key if the value is still cached it will be taken from the cache instead of running the method.</p>
<div class="ulist">
<ul>
<li>
<p><a href="http://static.javadoc.io/javax.cache/cache-api/1.0.0/javax/cache/annotation/CacheResult.html" class="bare">http://static.javadoc.io/javax.cache/cache-api/1.0.0/javax/cache/annotation/CacheResult.html</a></p>
</li>
</ul>
</div>
</li>
</ul>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
Remember that the value is not cached forever.
The length of time will be influenced by how you set your eviction policy, TTL and TTI.
Please see this discussion for the difference between TTL and TTI: <a href="http://stackoverflow.com/questions/2583429/how-to-differentiate-between-time-to-live-and-time-to-idle-in-ehcache" class="bare">http://stackoverflow.com/questions/2583429/how-to-differentiate-between-time-to-live-and-time-to-idle-in-ehcache</a>
</td>
</tr>
</table>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>@CachePut</strong> - Cache the value specified as the @CacheValue.
This is similar to @CacheResult but the difference is it will cache the @CacheValue every time the method is called.</p>
<div class="ulist">
<ul>
<li>
<p><a href="http://static.javadoc.io/javax.cache/cache-api/1.0.0/javax/cache/annotation/CachePut.html" class="bare">http://static.javadoc.io/javax.cache/cache-api/1.0.0/javax/cache/annotation/CachePut.html</a></p>
</li>
</ul>
</div>
</li>
<li>
<p><strong>@CacheRemove</strong> - removes entries from the specified cache that match the provided/generated key</p>
<div class="ulist">
<ul>
<li>
<p><a href="http://static.javadoc.io/javax.cache/cache-api/1.0.0/javax/cache/annotation/CacheRemove.html" class="bare">http://static.javadoc.io/javax.cache/cache-api/1.0.0/javax/cache/annotation/CacheRemove.html</a></p>
</li>
</ul>
</div>
</li>
<li>
<p><strong>@CacheRemoveAll</strong> - removes all elements in the specified cache</p>
<div class="ulist">
<ul>
<li>
<p><a href="http://static.javadoc.io/javax.cache/cache-api/1.0.0/javax/cache/annotation/CacheRemoveAll.html" class="bare">http://static.javadoc.io/javax.cache/cache-api/1.0.0/javax/cache/annotation/CacheRemoveAll.html</a></p>
</li>
</ul>
</div>
</li>
<li>
<p>The <strong>javax.cache.annotation</strong> package which includes all the JSR-107 annotations:</p>
<div class="ulist">
<ul>
<li>
<p><a href="http://www.javadoc.io/doc/javax.cache/cache-api/1.0.0" class="bare">http://www.javadoc.io/doc/javax.cache/cache-api/1.0.0</a></p>
</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="steps"><a class="anchor" href="#steps"></a>Steps</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Let&#8217;s get started!
Below are a few quick steps to get you up and running with Ehcache 3, Spring 4.1+ and JSR-107.
The entire example can be found on GitHub at <a href="https://github.com/gibsong/ehcache-jsr107-spring" class="bare">https://github.com/gibsong/ehcache-jsr107-spring</a></p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Create a maven Spring project.
Maven 3.2 or greater is required.</p>
</li>
<li>
<p>Add Ehcache 3 to your pom.xml.</p>
<div class="listingblock">
<div class="title">pom.xml</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="xml"> &lt;dependency&gt;
&lt;groupId&gt;org.ehcache&lt;/groupId&gt;
&lt;artifactId&gt;ehcache&lt;/artifactId&gt;
&lt;version&gt;3.0.0&lt;/version&gt; <i class="conum" data-value="1"></i><b>(1)</b>
&lt;/dependency&gt;</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Be sure to substitute the version number above with the version number of Ehcache that you want to use.</td>
</tr>
</table>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
The Ehcache 3 jar must be on the classpath!
Remove all existing caching provider jars from the classpath to ensure that the right implementation is used.
</td>
</tr>
</table>
</div>
</li>
<li>
<p>Add the jar for the JSR-107 API to the pom.xml</p>
<div class="listingblock">
<div class="title">pom.xml</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="xml"> &lt;dependency&gt;
&lt;groupId&gt;javax.cache&lt;/groupId&gt;
&lt;artifactId&gt;cache-api&lt;/artifactId&gt;
&lt;/dependency&gt;</code></pre>
</div>
</div>
</li>
<li>
<p>Add Spring boot jars</p>
<div class="listingblock">
<div class="title">pom.xml</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="xml"> &lt;parent&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt; <i class="conum" data-value="1"></i><b>(1)</b>
&lt;version&gt;1.3.2.RELEASE&lt;/version&gt;
&lt;/parent&gt;
...
&lt;dependencies&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-cache&lt;/artifactId&gt; <i class="conum" data-value="2"></i><b>(2)</b>
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt; <i class="conum" data-value="3"></i><b>(3)</b>
&lt;/dependency&gt;
...
&lt;dependencies&gt;</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Add the spring-boot-starter-parent parent project to use Spring boot</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Add the spring-boot-starter-cache to use Spring Framework&#8217;s caching support</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Add spring-boot-starter-web to use Spring MVC</td>
</tr>
</table>
</div>
</li>
<li>
<p>Set the <strong>spring.cache.jcache.config</strong> property to include the classpath and ehcache.xml file.
This needs to be done in the application.properties file.</p>
<div class="listingblock">
<div class="title">application.properties</div>
<div class="content">
<pre>spring.cache.jcache.config=classpath:ehcache.xml</pre>
</div>
</div>
</li>
<li>
<p>Enable caching.
This can be done in 1 of 2 ways:</p>
<div class="olist loweralpha">
<ol class="loweralpha" type="a">
<li>
<p>Enable with @EnableCaching annotation:</p>
<div class="listingblock">
<div class="title">SpringJsr107Ehcache3Application.java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java"> @EnableCaching
public class SpringJsr107Ehcache3Application
{
public static void main(String[] args)
{
SpringApplication.run(SpringJsr107Ehcache3Application.class, args);
}
}</code></pre>
</div>
</div>
</li>
<li>
<p>Or enable from the Spring xml configuration file by adding the following tag: &lt;cache:annotation-driven /&gt;</p>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="xml"> &lt;beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"&gt;
&lt;cache:annotation-driven /&gt;
&lt;/beans&gt;</code></pre>
</div>
</div>
</li>
</ol>
</div>
</li>
<li>
<p>Declare caching on a method by adding the @CacheResult annotation.</p>
<div class="listingblock">
<div class="title">PersonService.java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java"> @CacheResult <i class="conum" data-value="1"></i><b>(1)</b>
Person getPerson(int ssn)
{
switch (ssn)
{
case 123456789:
return new Person(ssn, "Geoff", "Gibson");
case 987654321:
return new Person(ssn, "Cory", "Beck");
default:
return new Person(ssn,"John","Doe");
}
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Add the @CacheResult annotation above the method.
In this case the key is the "int ssn" parameter and the value cached is a Person instance.
So if you call this method with ssn="123456789", the Person(ssn, "Geoff", "Gibson") will be returned and cached.
The next time the getPerson(&#8230;&#8203;) method is called with ssn="123456789" (assuming the key/value wasn&#8217;t evicted from the cache) the method won&#8217;t run and instead it will grab Person(ssn, "Geoff", "Gibson") from the cache and return it.</td>
</tr>
</table>
</div>
</li>
<li>
<p>Configure ehcache.xml</p>
<div class="listingblock">
<div class="title">ehcache.xml</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="xml">&lt;config
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://www.ehcache.org/v3' <i class="conum" data-value="1"></i><b>(1)</b>
xmlns:jsr107='http://www.ehcache.org/v3/jsr107'&gt; <i class="conum" data-value="2"></i><b>(2)</b>
&lt;service&gt;
&lt;jsr107:defaults&gt;
&lt;jsr107:cache name="people" template="heap-cache"/&gt; <i class="conum" data-value="3"></i><b>(3)</b>
&lt;/jsr107:defaults&gt;
&lt;/service&gt;
&lt;cache-template name="heap-cache"&gt;
&lt;listeners&gt; <i class="conum" data-value="4"></i><b>(4)</b>
&lt;listener&gt;
&lt;class&gt;org.terracotta.ehcache.EventLogger&lt;/class&gt;
&lt;event-firing-mode&gt;ASYNCHRONOUS&lt;/event-firing-mode&gt;
&lt;event-ordering-mode&gt;UNORDERED&lt;/event-ordering-mode&gt;
&lt;events-to-fire-on&gt;CREATED&lt;/events-to-fire-on&gt; <i class="conum" data-value="5"></i><b>(5)</b>
&lt;events-to-fire-on&gt;UPDATED&lt;/events-to-fire-on&gt; <i class="conum" data-value="6"></i><b>(6)</b>
&lt;events-to-fire-on&gt;EXPIRED&lt;/events-to-fire-on&gt; <i class="conum" data-value="7"></i><b>(7)</b>
&lt;events-to-fire-on&gt;REMOVED&lt;/events-to-fire-on&gt; <i class="conum" data-value="8"></i><b>(8)</b>
&lt;events-to-fire-on&gt;EVICTED&lt;/events-to-fire-on&gt; <i class="conum" data-value="9"></i><b>(9)</b>
&lt;/listener&gt;
&lt;/listeners&gt;
&lt;resources&gt;
&lt;heap unit="entries"&gt;2000&lt;/heap&gt; <i class="conum" data-value="10"></i><b>(10)</b>
&lt;offheap unit="MB"&gt;100&lt;/offheap&gt; <i class="conum" data-value="11"></i><b>(11)</b>
&lt;/resources&gt;
&lt;/cache-template&gt;
&lt;/config&gt;</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>The core namespace, the xsd can be found here: <a href="http://www.ehcache.org/schema/ehcache-core-3.0.xsd" class="bare">http://www.ehcache.org/schema/ehcache-core-3.0.xsd</a></td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>The JSR-107 namespace, the xsd can be found here: <a href="http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd" class="bare">http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd</a></td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Defines a cache with alias "people", which inherits from cache-template "heap-cache"</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>This section allows you to add cache event listeners.
I added a listener for 5 events.
Each event will be logged, by the EventLogger class, when it occurs.</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>Defines a CREATED event, when an entry is added to the cache, with this listener.</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>Defines an UPDATED event, when an entry is updated in the cache, with this listener.
However in this example this one will never be used.
I just added it as an example.</td>
</tr>
<tr>
<td><i class="conum" data-value="7"></i><b>7</b></td>
<td>Defines an EXPIRED event, when an entry is expired from the cache, with this listener.</td>
</tr>
<tr>
<td><i class="conum" data-value="8"></i><b>8</b></td>
<td>Defines an REMOVED event, when an entry is removed from the cache, with this listener.</td>
</tr>
<tr>
<td><i class="conum" data-value="9"></i><b>9</b></td>
<td>Defines an EVICTED event, when an entry is evicted from the cache, with this listener.</td>
</tr>
<tr>
<td><i class="conum" data-value="10"></i><b>10</b></td>
<td>The heap is configured to allow 2000 entries</td>
</tr>
<tr>
<td><i class="conum" data-value="11"></i><b>11</b></td>
<td>The offheap storage is configured with 100 MB of space.
Remember the unit of measure is case sensitive.</td>
</tr>
</table>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
XML Configuration Documentation: <a href="http://www.ehcache.org/documentation/3.0/xml.html" class="bare">http://www.ehcache.org/documentation/3.0/xml.html</a>
</td>
</tr>
</table>
</div>
</li>
<li>
<p>Create a cache by implementing the JCacheManagerCustomizer.customize(CacheManager cacheManager) method, which will be invoked before the CacheManager is used.</p>
<div class="listingblock">
<div class="title">PersonService.java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java"> @Component
public static class CachingSetup implements JCacheManagerCustomizer
{
@Override
public void customize(CacheManager cacheManager)
{
cacheManager.createCache("people", new MutableConfiguration&lt;&gt;() <i class="conum" data-value="1"></i><b>(1)</b>
.setExpiryPolicyFactory(TouchedExpiryPolicy.factoryOf(new Duration(SECONDS, 10))) <i class="conum" data-value="2"></i><b>(2)</b>
.setStoreByValue(false)
.setStatisticsEnabled(true));
}
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Creates a cache with an alias of "people".</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>This line sets the expiration policy.
In this case we set it to 10 seconds.
Thus, if an entry hasn&#8217;t been touched (created, updated, or accessed) for the last 10 seconds it will be evicted.</td>
</tr>
</table>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
JCacheManagerCustomizer API: <a href="https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/cache/JCacheManagerCustomizer.html" class="bare">https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/cache/JCacheManagerCustomizer.html</a>
</td>
</tr>
</table>
</div>
</li>
<li>
<p>Now you can build the project by running the following maven command: mvn clean install</p>
</li>
<li>
<p>To run the application use this maven command: mvn spring-boot:run</p>
</li>
<li>
<p>To make a get request to the application use the following url: <a href="http://localhost:8080/person/{ssn}" class="bare">http://localhost:8080/person/{ssn}</a>
IMPORTANT: Remember to replace {ssn} in the url with an integer value.
123456789 and 987654321 are mapped to unique Person instances, while anything else maps to a generic Person instance.</p>
</li>
</ol>
</div>
</div>
</div>
<div class="sect1">
<h2 id="conclusion"><a class="anchor" href="#conclusion"></a>Conclusion</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Wow wasn&#8217;t that easy!
I hope you enjoyed my quick start tutorial on how to use Ehcache 3 with Spring 4.1+ and JSR-107.
If you have any questions please feel free to send them to me at <a href="mailto:[email protected]">[email protected]</a> and I will be happy to help out.</p>
</div>
</div>
</div>
<p><a href="https://www.ehcache.org/blog/2016/05/18/ehcache3_jsr107_spring.html">Ehcache 3, JSR-107 and Spring 4.2</a> was originally published by Geoff Gibson at <a href="https://www.ehcache.org">Ehcache</a> on May 18, 2016.</p></content>
</entry>
<entry>
<title type="html"><![CDATA[Custom Serializers]]></title>
<link rel="alternate" type="text/html" href="https://www.ehcache.org/blog/2016/05/12/ehcache3-serializers.html" />
<id>https://www.ehcache.org/blog/2016/05/12/ehcache3-serializers</id>
<published>2016-05-12T15:45:00+00:00</published>
<updated>2016-05-12T15:45:00+00:00</updated>
<author>
<name>Albin Suresh</name>
<uri>https://www.ehcache.org</uri>
</author>
<content type="html"><div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>The Ehcache 3 documentation at <a href="http://www.ehcache.org/documentation/3.0/serializers-copiers.html#serializers">Serializers</a>
gives you an overview of how to use custom serializers with a cache.
The section on <a href="http://www.ehcache.org/documentation/3.0/serializers-copiers.html#persistent-vs-transient-caches">Persistent and Transient Serializers</a>
briefly covers the serializer contracts that must be honored while writing custom serializers to be used with
persistent/transient caches.</p>
</div>
<div class="paragraph">
<p>This article explains how you can write a transient/persistent custom serializer that works with Ehcache.
Here we discuss the significance of transient serializers and persistent serializers in detail through some
practical examples.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="serializer-types"><a class="anchor" href="#serializer-types"></a>Serializer types</h2>
<div class="sectionbody">
<div class="paragraph">
<p>As indicated in the Ehcache documentation, serializers require a single argument constructor or a double-argument
constructor or both based on the type of cache they are used in.
The single-argument constructor is fit to be used with transient caches and the ones with the double-argument constructor can be used with persistent caches.
An implementation having both the constructors can be used with both <em>persistent</em> and <em>transient</em> caches.</p>
</div>
<div class="paragraph">
<p>Hmm&#8230;&#8203; So what does that really mean?</p>
</div>
<div class="paragraph">
<p>If you look at the custom serializer implementations in the GettingStarted samples they are all have both the constructors
and if you look at the code they don&#8217;t do anything different.
It&#8217;s all standard java serialization.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>So what difference do the constructors make?</p>
</li>
<li>
<p>What is a <em>transient</em> serializer with single-argument constructor?</p>
</li>
<li>
<p>How do I implement a <em>persistent</em> serializer with the double-argument constructor?</p>
</li>
<li>
<p>When would I use both?</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Read along for the answers to these questions.</p>
</div>
<div class="paragraph">
<p>These constructors are associated with the state of the serializer implementations.
So if your custom serializer doesn&#8217;t have any state associated with it; that affects the serialization and
deserialization logic; then that is a serializer implementation that can safely be used with transient and persistent
caches. Such serializers would have both the constructors.
If you look at the <code>LongSerializer</code> or <code>StringSerializer</code> implementations in the GettingStarted samples, they don&#8217;t have
any state that the serialization and deserialization depend on.</p>
</div>
<div class="paragraph">
<p>So what are these serializers with <strong>state</strong>? I&#8217;ll try to explain that with some examples in the subsequent sections.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
The code samples in this article were compiled and tested with Ehcache v3.0.0.
Complete samples can be found at <a href="https://github.com/albinsuresh/ehcache-demo" class="bare">https://github.com/albinsuresh/ehcache-demo</a>
</td>
</tr>
</table>
</div>
<div class="sect2">
<h3 id="stateful-serializers"><a class="anchor" href="#stateful-serializers"></a>Stateful serializers</h3>
<div class="paragraph">
<p>I have an application that deals with fruits. So I have a <em>fruits</em> cache <code>Cache&lt;Long, String&gt;</code> that holds the mappings
from fruit ids to fruit names.
If this cache is a multi-tiered one then the keys and values will be stored in their serialized form in the
non-heap tiers.
For simplicity I&#8217;ll restrict the scope of our discussion only to the values that are fruit names of type <code>String</code>.
I can use standard Java serialization to serialize these values.
But for some reason I wanted to reduce the amount of serialized data.
So instead of serializing the strings directly I decided to map all the fruit names to some integer and store those
serialized integers instead of strings thinking that it&#8217;d save some space(dumb, huh?).
Since this serializer is designed specifically for the fruits cache, I was fairly confident that the integer range would
be more than enough to handle all possible fruit names on this planet.
And here is the serializer implementation that I came up with:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">public class SimpleTransientStringSerializer implements Serializer&lt;String&gt; {
protected Map&lt;Integer, String&gt; idStringMap = new HashMap&lt;Integer, String&gt;();
protected Map&lt;String, Integer&gt; stringIdMap = new HashMap&lt;String, Integer&gt;();
protected int id = 0;
public SimpleTransientStringSerializer(ClassLoader loader) {
//no-op
}
@Override
public ByteBuffer serialize(final String object) throws SerializerException {
Integer currentId = stringIdMap.get(object);
if(currentId == null) {
stringIdMap.put(object, id);
idStringMap.put(id, object);
currentId = id++;
}
ByteBuffer buff = ByteBuffer.allocate(4);
buff.putInt(currentId).flip();
return buff;
}
@Override
public String read(final ByteBuffer binary) throws ClassNotFoundException, SerializerException {
Integer mapping = binary.getInt();
String obj = idStringMap.get(mapping);
if(obj == null) {
throw new SerializerException("Unable to serialize: " + binary.array() + ". No value mapping found for " + mapping);
}
return obj;
}
@Override
public boolean equals(final String object, final ByteBuffer binary) throws ClassNotFoundException, SerializerException {
return object.equals(read(binary));
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>In short this is what the above serializer does: Whenever it gets a string(the fruit name, in our application) to be
serialized it checks if there is a mapping that exists already for that name in <code>stringIdMap</code>.
If yes, the mapped integer is retrieved from the map and that integer value is serialized.
If a mapping is not found, we generate a new <code>id</code> for the new fruit name add it to both the maps that we preserve
(<code>stringIdMap</code> and <code>idStringMap</code>) and then serialize this newly generated id.
Now on deserialization, the same <code>idStringMap</code> map is used to retrieve the fruit names from the deserialised integer
values.</p>
</div>
<div class="paragraph">
<p>So in the above serializer, the <code>idStringMap</code>, <code>stringIdMap</code> and the <code>id</code> constitutes the <em>state</em> of the serializer.
The serialization and deserialization depends on this state and would not work properly without that state.
This serializer has the single-argument constructor making it fit to be used with transient caches.
So now that we have a state-full serializer understanding the idea of <em>transient</em> and <em>persistent</em> serializers would be
simpler.</p>
</div>
<div class="paragraph">
<p>Here is a sample code that uses the <code>SimpleTransientStringSerializer</code> with a cache:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().build(true);
CacheConfiguration&lt;Long, String&gt; cacheConfig =
CacheConfigurationBuilder.newCacheConfigurationBuilder(
Long.class, String.class, ResourcePoolsBuilder.heap(10).offheap(5, MemoryUnit.MB)) <i class="conum" data-value="1"></i><b>(1)</b>
.withValueSerializer(SimpleTransientStringSerializer.class) <i class="conum" data-value="2"></i><b>(2)</b>
.build();
Cache&lt;Long, String&gt; fruitsCache = cacheManager.createCache("fruitsCache", cacheConfig);
fruitsCache.put(1L, "apple");
fruitsCache.put(2L, "orange");
fruitsCache.put(3L, "mango");
assertThat(fruitsCache.get(1L), is("apple")); <i class="conum" data-value="3"></i><b>(3)</b>
assertThat(fruitsCache.get(3L), is("mango"));
assertThat(fruitsCache.get(2L), is("orange"));
assertThat(fruitsCache.get(1L), is("apple"));</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Create a multi-tiered cache that requires key and value serialization.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Configure a serializer for the values. The <code>SimpleTransientStringSerializer</code> in this case. For the sake of simplicity
we have omitted key serializer. Since one is not provided explicitly, ehcache would provide default serializers to
perform the key serialization.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Verify that the cache/serializer works.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>In the previous section we demonstrated the use of a transient serializer.
We used that serializer with a transient cache and everything works just fine.
Now imagine what would happen if we use the same serializer with a persistent cache.
Everything would work as long as your application is running. Once you close the cache manager or end the application
the data associated with the cache will be persisted so that the same data will be available on a restart.
But there is a serious problem. The following piece of code would demonstrate that:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">CacheConfiguration&lt;Long, String&gt; cacheConfig =
CacheConfigurationBuilder.newCacheConfigurationBuilder(
Long.class, String.class,
ResourcePoolsBuilder.heap(10).disk(10, MemoryUnit.MB, true)) <i class="conum" data-value="1"></i><b>(1)</b>
.withValueSerializer(SimpleTransientStringSerializer.class)
.build();
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.with(new CacheManagerPersistenceConfiguration(new File(PERSISTENCE_PATH))) <i class="conum" data-value="2"></i><b>(2)</b>
.withCache("fruitsCache", cacheConfig)
.build(true);
Cache&lt;Long, String&gt; fruitsCache = cacheManager.getCache("fruitsCache", Long.class, String.class); <i class="conum" data-value="3"></i><b>(3)</b>
fruitsCache.put(1L, "apple");
fruitsCache.put(2L, "mango");
fruitsCache.put(3L, "orange"); <i class="conum" data-value="4"></i><b>(4)</b>
assertThat(fruitsCache.get(1L), is("apple")); <i class="conum" data-value="5"></i><b>(5)</b>
cacheManager.close(); <i class="conum" data-value="6"></i><b>(6)</b>
cacheManager.init(); <i class="conum" data-value="7"></i><b>(7)</b>
fruitsCache = cacheManager.getCache("fruitsCache", Long.class, String.class); <i class="conum" data-value="8"></i><b>(8)</b>
assertThat(fruitsCache.get(1L), is("apple")); <i class="conum" data-value="9"></i><b>(9)</b></code></pre>
</div>