BAEL-1368: infinispan article (#3633)
This commit is contained in:
parent
1c043dc202
commit
6eeff13c45
|
@ -649,6 +649,11 @@
|
|||
<artifactId>google-http-client-gson</artifactId>
|
||||
<version>${googleclient.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.infinispan</groupId>
|
||||
<artifactId>infinispan-core</artifactId>
|
||||
<version>${infinispan.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--Java Docker API Client-->
|
||||
<dependency>
|
||||
|
@ -811,5 +816,6 @@
|
|||
<docker.version>3.0.14</docker.version>
|
||||
<tomcat.version>8.5.24</tomcat.version>
|
||||
<async.http.client.version>2.2.0</async.http.client.version>
|
||||
<infinispan.version>9.1.5.Final</infinispan.version>
|
||||
</properties>
|
||||
</project>
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
package com.baeldung.infinispan;
|
||||
|
||||
import com.baeldung.infinispan.listener.CacheListener;
|
||||
import org.infinispan.Cache;
|
||||
import org.infinispan.configuration.cache.Configuration;
|
||||
import org.infinispan.configuration.cache.ConfigurationBuilder;
|
||||
import org.infinispan.eviction.EvictionType;
|
||||
import org.infinispan.manager.DefaultCacheManager;
|
||||
import org.infinispan.transaction.LockingMode;
|
||||
import org.infinispan.transaction.TransactionMode;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class CacheConfiguration {
|
||||
|
||||
public static final String SIMPLE_HELLO_WORLD_CACHE = "simple-hello-world-cache";
|
||||
public static final String EXPIRING_HELLO_WORLD_CACHE = "expiring-hello-world-cache";
|
||||
public static final String EVICTING_HELLO_WORLD_CACHE = "evicting-hello-world-cache";
|
||||
public static final String PASSIVATING_HELLO_WORLD_CACHE = "passivating-hello-world-cache";
|
||||
public static final String TRANSACTIONAL_CACHE = "transactional-cache";
|
||||
|
||||
public DefaultCacheManager cacheManager() {
|
||||
DefaultCacheManager cacheManager = new DefaultCacheManager();
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
public Cache<String, Integer> transactionalCache(DefaultCacheManager cacheManager, CacheListener listener) {
|
||||
return this.buildCache(TRANSACTIONAL_CACHE, cacheManager, listener, transactionalConfiguration());
|
||||
}
|
||||
|
||||
public Cache<String, String> simpleHelloWorldCache(DefaultCacheManager cacheManager, CacheListener listener) {
|
||||
return this.buildCache(SIMPLE_HELLO_WORLD_CACHE, cacheManager, listener, new ConfigurationBuilder().build());
|
||||
}
|
||||
|
||||
public Cache<String, String> expiringHelloWorldCache(DefaultCacheManager cacheManager, CacheListener listener) {
|
||||
return this.buildCache(EXPIRING_HELLO_WORLD_CACHE, cacheManager, listener, expiringConfiguration());
|
||||
}
|
||||
|
||||
public Cache<String, String> evictingHelloWorldCache(DefaultCacheManager cacheManager, CacheListener listener) {
|
||||
return this.buildCache(EVICTING_HELLO_WORLD_CACHE, cacheManager, listener, evictingConfiguration());
|
||||
}
|
||||
|
||||
public Cache<String, String> passivatingHelloWorldCache(DefaultCacheManager cacheManager, CacheListener listener) {
|
||||
return this.buildCache(PASSIVATING_HELLO_WORLD_CACHE, cacheManager, listener, passivatingConfiguration());
|
||||
}
|
||||
|
||||
private <K, V> Cache<K, V> buildCache(String cacheName, DefaultCacheManager cacheManager,
|
||||
CacheListener listener, Configuration configuration) {
|
||||
|
||||
cacheManager.defineConfiguration(cacheName, configuration);
|
||||
Cache<K, V> cache = cacheManager.getCache(cacheName);
|
||||
cache.addListener(listener);
|
||||
return cache;
|
||||
}
|
||||
|
||||
private Configuration expiringConfiguration() {
|
||||
return new ConfigurationBuilder().expiration().lifespan(1, TimeUnit.SECONDS)
|
||||
.build();
|
||||
}
|
||||
|
||||
private Configuration evictingConfiguration() {
|
||||
return new ConfigurationBuilder()
|
||||
.memory().evictionType(EvictionType.COUNT).size(1)
|
||||
.build();
|
||||
}
|
||||
|
||||
private Configuration passivatingConfiguration() {
|
||||
return new ConfigurationBuilder()
|
||||
.memory().evictionType(EvictionType.COUNT).size(1)
|
||||
.persistence()
|
||||
.passivation(true)
|
||||
.addSingleFileStore()
|
||||
.purgeOnStartup(true)
|
||||
.location(System.getProperty("java.io.tmpdir"))
|
||||
.build();
|
||||
}
|
||||
|
||||
private Configuration transactionalConfiguration() {
|
||||
return new ConfigurationBuilder()
|
||||
.transaction().transactionMode(TransactionMode.TRANSACTIONAL)
|
||||
.lockingMode(LockingMode.PESSIMISTIC)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package com.baeldung.infinispan.listener;
|
||||
|
||||
import org.infinispan.notifications.Listener;
|
||||
import org.infinispan.notifications.cachelistener.annotation.*;
|
||||
import org.infinispan.notifications.cachelistener.event.*;
|
||||
|
||||
@Listener
|
||||
public class CacheListener {
|
||||
|
||||
@CacheEntryCreated
|
||||
public void entryCreated(CacheEntryCreatedEvent<String, String> event) {
|
||||
this.printLog("Adding key '" + event.getKey() + "' to cache", event);
|
||||
}
|
||||
|
||||
@CacheEntryExpired
|
||||
public void entryExpired(CacheEntryExpiredEvent<String, String> event) {
|
||||
this.printLog("Expiring key '" + event.getKey() + "' from cache", event);
|
||||
}
|
||||
|
||||
@CacheEntryVisited
|
||||
public void entryVisited(CacheEntryVisitedEvent<String, String> event) {
|
||||
this.printLog("Key '" + event.getKey() + "' was visited", event);
|
||||
}
|
||||
|
||||
@CacheEntryActivated
|
||||
public void entryActivated(CacheEntryActivatedEvent<String, String> event) {
|
||||
this.printLog("Activating key '" + event.getKey() + "' on cache", event);
|
||||
}
|
||||
|
||||
@CacheEntryPassivated
|
||||
public void entryPassivated(CacheEntryPassivatedEvent<String, String> event) {
|
||||
this.printLog("Passivating key '" + event.getKey() + "' from cache", event);
|
||||
}
|
||||
|
||||
@CacheEntryLoaded
|
||||
public void entryLoaded(CacheEntryLoadedEvent<String, String> event) {
|
||||
this.printLog("Loading key '" + event.getKey() + "' to cache", event);
|
||||
}
|
||||
|
||||
@CacheEntriesEvicted
|
||||
public void entriesEvicted(CacheEntriesEvictedEvent<String, String> event) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
event.getEntries().entrySet().forEach((e) ->
|
||||
builder.append(e.getKey() + ", ")
|
||||
);
|
||||
System.out.println("Evicting following entries from cache: " + builder.toString());
|
||||
}
|
||||
|
||||
private void printLog(String log, CacheEntryEvent event) {
|
||||
if (!event.isPre()) {
|
||||
System.out.println(log);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.baeldung.infinispan.repository;
|
||||
|
||||
public class HelloWorldRepository {
|
||||
|
||||
public String getHelloWorld() {
|
||||
try {
|
||||
System.out.println("Executing some heavy query");
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "Hello World!";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package com.baeldung.infinispan.service;
|
||||
|
||||
import com.baeldung.infinispan.listener.CacheListener;
|
||||
import com.baeldung.infinispan.repository.HelloWorldRepository;
|
||||
import org.infinispan.Cache;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class HelloWorldService {
|
||||
|
||||
private final HelloWorldRepository repository;
|
||||
|
||||
private final Cache<String, String> simpleHelloWorldCache;
|
||||
private final Cache<String, String> expiringHelloWorldCache;
|
||||
private final Cache<String, String> evictingHelloWorldCache;
|
||||
private final Cache<String, String> passivatingHelloWorldCache;
|
||||
|
||||
public HelloWorldService(HelloWorldRepository repository, CacheListener listener,
|
||||
Cache<String, String> simpleHelloWorldCache,
|
||||
Cache<String, String> expiringHelloWorldCache,
|
||||
Cache<String, String> evictingHelloWorldCache,
|
||||
Cache<String, String> passivatingHelloWorldCache) {
|
||||
|
||||
this.repository = repository;
|
||||
|
||||
this.simpleHelloWorldCache = simpleHelloWorldCache;
|
||||
this.expiringHelloWorldCache = expiringHelloWorldCache;
|
||||
this.evictingHelloWorldCache = evictingHelloWorldCache;
|
||||
this.passivatingHelloWorldCache = passivatingHelloWorldCache;
|
||||
}
|
||||
|
||||
public String findSimpleHelloWorld() {
|
||||
String cacheKey = "simple-hello";
|
||||
String helloWorld = simpleHelloWorldCache.get(cacheKey);
|
||||
if (helloWorld == null) {
|
||||
helloWorld = repository.getHelloWorld();
|
||||
simpleHelloWorldCache.put(cacheKey, helloWorld);
|
||||
}
|
||||
return helloWorld;
|
||||
}
|
||||
|
||||
public String findExpiringHelloWorld() {
|
||||
String cacheKey = "expiring-hello";
|
||||
String helloWorld = simpleHelloWorldCache.get(cacheKey);
|
||||
if (helloWorld == null) {
|
||||
helloWorld = repository.getHelloWorld();
|
||||
simpleHelloWorldCache.put(cacheKey, helloWorld, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
return helloWorld;
|
||||
}
|
||||
|
||||
public String findIdleHelloWorld() {
|
||||
String cacheKey = "idle-hello";
|
||||
String helloWorld = simpleHelloWorldCache.get(cacheKey);
|
||||
if (helloWorld == null) {
|
||||
helloWorld = repository.getHelloWorld();
|
||||
simpleHelloWorldCache.put(cacheKey, helloWorld, -1, TimeUnit.SECONDS, 10, TimeUnit.SECONDS);
|
||||
}
|
||||
return helloWorld;
|
||||
}
|
||||
|
||||
public String findSimpleHelloWorldInExpiringCache() {
|
||||
String cacheKey = "simple-hello";
|
||||
String helloWorld = expiringHelloWorldCache.get(cacheKey);
|
||||
if (helloWorld == null) {
|
||||
helloWorld = repository.getHelloWorld();
|
||||
expiringHelloWorldCache.put(cacheKey, helloWorld);
|
||||
}
|
||||
return helloWorld;
|
||||
}
|
||||
|
||||
public String findEvictingHelloWorld(String key) {
|
||||
String value = evictingHelloWorldCache.get(key);
|
||||
if(value == null) {
|
||||
value = repository.getHelloWorld();
|
||||
evictingHelloWorldCache.put(key, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public String findPassivatingHelloWorld(String key) {
|
||||
String value = passivatingHelloWorldCache.get(key);
|
||||
if(value == null) {
|
||||
value = repository.getHelloWorld();
|
||||
passivatingHelloWorldCache.put(key, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package com.baeldung.infinispan.service;
|
||||
|
||||
import org.infinispan.Cache;
|
||||
import org.springframework.util.StopWatch;
|
||||
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
public class TransactionalService {
|
||||
|
||||
private final Cache<String, Integer> transactionalCache;
|
||||
|
||||
private static final String KEY = "key";
|
||||
|
||||
public TransactionalService(Cache<String, Integer> transactionalCache) {
|
||||
this.transactionalCache = transactionalCache;
|
||||
|
||||
transactionalCache.put(KEY, 0);
|
||||
}
|
||||
|
||||
public Integer getQuickHowManyVisits() {
|
||||
try {
|
||||
TransactionManager tm = transactionalCache.getAdvancedCache().getTransactionManager();
|
||||
tm.begin();
|
||||
Integer howManyVisits = transactionalCache.get(KEY);
|
||||
howManyVisits++;
|
||||
System.out.println("Ill try to set HowManyVisits to " + howManyVisits);
|
||||
StopWatch watch = new StopWatch();
|
||||
watch.start();
|
||||
transactionalCache.put(KEY, howManyVisits);
|
||||
watch.stop();
|
||||
System.out.println("I was able to set HowManyVisits to " + howManyVisits +
|
||||
" after waiting " + watch.getTotalTimeSeconds() + " seconds");
|
||||
|
||||
tm.commit();
|
||||
return howManyVisits;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void startBackgroundBatch() {
|
||||
try {
|
||||
TransactionManager tm = transactionalCache.getAdvancedCache().getTransactionManager();
|
||||
tm.begin();
|
||||
transactionalCache.put(KEY, 1000);
|
||||
System.out.println("HowManyVisits should now be 1000, " +
|
||||
"but we are holding the transaction");
|
||||
Thread.sleep(1000L);
|
||||
tm.rollback();
|
||||
System.out.println("The slow batch suffered a rollback");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.baeldung.infinispan;
|
||||
|
||||
import com.baeldung.infinispan.listener.CacheListener;
|
||||
import com.baeldung.infinispan.repository.HelloWorldRepository;
|
||||
import com.baeldung.infinispan.service.HelloWorldService;
|
||||
import com.baeldung.infinispan.service.TransactionalService;
|
||||
import org.infinispan.Cache;
|
||||
import org.infinispan.manager.DefaultCacheManager;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
public class ConfigurationTest {
|
||||
|
||||
private DefaultCacheManager cacheManager;
|
||||
|
||||
private HelloWorldRepository repository = new HelloWorldRepository();
|
||||
|
||||
protected HelloWorldService helloWorldService;
|
||||
protected TransactionalService transactionalService;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
CacheConfiguration configuration = new CacheConfiguration();
|
||||
CacheListener listener = new CacheListener();
|
||||
|
||||
cacheManager = configuration.cacheManager();
|
||||
|
||||
Cache<String, Integer> transactionalCache =
|
||||
configuration.transactionalCache(cacheManager, listener);
|
||||
|
||||
Cache<String, String> simpleHelloWorldCache =
|
||||
configuration.simpleHelloWorldCache(cacheManager, listener);
|
||||
|
||||
Cache<String, String> expiringHelloWorldCache =
|
||||
configuration.expiringHelloWorldCache(cacheManager, listener);
|
||||
|
||||
Cache<String, String> evictingHelloWorldCache =
|
||||
configuration.evictingHelloWorldCache(cacheManager, listener);
|
||||
|
||||
Cache<String, String> passivatingHelloWorldCache =
|
||||
configuration.passivatingHelloWorldCache(cacheManager, listener);
|
||||
|
||||
this.helloWorldService = new HelloWorldService(repository,
|
||||
listener, simpleHelloWorldCache, expiringHelloWorldCache, evictingHelloWorldCache,
|
||||
passivatingHelloWorldCache);
|
||||
|
||||
this.transactionalService = new TransactionalService(transactionalCache);
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
cacheManager.stop();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
package com.baeldung.infinispan.service;
|
||||
|
||||
import com.baeldung.infinispan.ConfigurationTest;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Java6Assertions.assertThat;
|
||||
|
||||
public class HelloWorldServiceUnitTest extends ConfigurationTest {
|
||||
|
||||
@Test
|
||||
public void whenGetIsCalledTwoTimes_thenTheSecondShouldHitTheCache() {
|
||||
long milis = System.currentTimeMillis();
|
||||
helloWorldService.findSimpleHelloWorld();
|
||||
long executionTime = System.currentTimeMillis() - milis;
|
||||
|
||||
assertThat(executionTime).isGreaterThanOrEqualTo(1000);
|
||||
|
||||
milis = System.currentTimeMillis();
|
||||
helloWorldService.findSimpleHelloWorld();
|
||||
executionTime = System.currentTimeMillis() - milis;
|
||||
|
||||
assertThat(executionTime).isLessThan(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenGetIsCalledTwoTimesQuickly_thenTheSecondShouldHitTheCache() {
|
||||
long milis = System.currentTimeMillis();
|
||||
helloWorldService.findExpiringHelloWorld();
|
||||
long executionTime = System.currentTimeMillis() - milis;
|
||||
|
||||
assertThat(executionTime).isGreaterThanOrEqualTo(1000);
|
||||
|
||||
milis = System.currentTimeMillis();
|
||||
helloWorldService.findExpiringHelloWorld();
|
||||
executionTime = System.currentTimeMillis() - milis;
|
||||
|
||||
assertThat(executionTime).isLessThan(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenGetIsCalledTwoTimesSparsely_thenNeitherShouldHitTheCache()
|
||||
throws InterruptedException {
|
||||
|
||||
long milis = System.currentTimeMillis();
|
||||
helloWorldService.findSimpleHelloWorldInExpiringCache();
|
||||
long executionTime = System.currentTimeMillis() - milis;
|
||||
|
||||
assertThat(executionTime).isGreaterThanOrEqualTo(1000);
|
||||
|
||||
Thread.sleep(1100);
|
||||
|
||||
milis = System.currentTimeMillis();
|
||||
helloWorldService.findSimpleHelloWorldInExpiringCache();
|
||||
executionTime = System.currentTimeMillis() - milis;
|
||||
|
||||
assertThat(executionTime).isGreaterThanOrEqualTo(1000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenOneEntryIsConfigured_whenTwoAreAdded_thenFirstShouldntBeAvailable()
|
||||
throws InterruptedException {
|
||||
|
||||
long milis = System.currentTimeMillis();
|
||||
helloWorldService.findEvictingHelloWorld("key 1");
|
||||
long executionTime = System.currentTimeMillis() - milis;
|
||||
|
||||
assertThat(executionTime).isGreaterThanOrEqualTo(1000);
|
||||
|
||||
milis = System.currentTimeMillis();
|
||||
helloWorldService.findEvictingHelloWorld("key 2");
|
||||
executionTime = System.currentTimeMillis() - milis;
|
||||
|
||||
assertThat(executionTime).isGreaterThanOrEqualTo(1000);
|
||||
|
||||
milis = System.currentTimeMillis();
|
||||
helloWorldService.findEvictingHelloWorld("key 1");
|
||||
executionTime = System.currentTimeMillis() - milis;
|
||||
|
||||
assertThat(executionTime).isGreaterThanOrEqualTo(1000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenOneEntryIsConfigured_whenTwoAreAdded_thenTheFirstShouldBeAvailable()
|
||||
throws InterruptedException {
|
||||
|
||||
long milis = System.currentTimeMillis();
|
||||
helloWorldService.findPassivatingHelloWorld("key 1");
|
||||
long executionTime = System.currentTimeMillis() - milis;
|
||||
|
||||
assertThat(executionTime).isGreaterThanOrEqualTo(1000);
|
||||
|
||||
milis = System.currentTimeMillis();
|
||||
helloWorldService.findPassivatingHelloWorld("key 2");
|
||||
executionTime = System.currentTimeMillis() - milis;
|
||||
|
||||
assertThat(executionTime).isGreaterThanOrEqualTo(1000);
|
||||
|
||||
milis = System.currentTimeMillis();
|
||||
helloWorldService.findPassivatingHelloWorld("key 1");
|
||||
executionTime = System.currentTimeMillis() - milis;
|
||||
|
||||
assertThat(executionTime).isLessThan(100);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.baeldung.infinispan.service;
|
||||
|
||||
import com.baeldung.infinispan.ConfigurationTest;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Java6Assertions.assertThat;
|
||||
|
||||
public class TransactionalServiceUnitTest extends ConfigurationTest {
|
||||
|
||||
@Test
|
||||
public void whenLockingAnEntry_thenItShouldBeInaccessible() throws InterruptedException {
|
||||
Runnable backGroundJob = () -> transactionalService.startBackgroundBatch();
|
||||
Thread backgroundThread = new Thread(backGroundJob);
|
||||
transactionalService.getQuickHowManyVisits();
|
||||
backgroundThread.start();
|
||||
Thread.sleep(100); //lets wait our thread warm up
|
||||
long milis = System.currentTimeMillis();
|
||||
transactionalService.getQuickHowManyVisits();
|
||||
long executionTime = System.currentTimeMillis() - milis;
|
||||
|
||||
assertThat(executionTime).isGreaterThan(500).isLessThan(1000);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue