Last time, I used SpringDataGeode to create a SpringBoot application that uses an in-memory data grid, and used SpringData to confirm that the persisted data is shared between the two applications.
Creating an application using SpringDataGeode
This time I tried to implement event processing using the mechanism of in-memory data grid think.
Implement as shown in the figure below.
--First, implement a listener that detects changes in Region
UserRegionListener.java
package spring.geode.geodeCommon.listener;
import java.time.LocalDateTime;
import org.apache.geode.cache.CacheListener;
import org.apache.geode.cache.EntryEvent;
import org.apache.geode.cache.RegionEvent;
import spring.geode.geodeCommon.model.User;
import spring.geode.geodeCommon.region.UserRegion;
/**
* {@link UserRegion}Listener that detects changes in
*
*/
public class UserRegionListener implements CacheListener<Integer,User> {
public void afterCreate(EntryEvent<Integer,User> event) {
System.out.println(LocalDateTime.now());
System.out.println("afterCreate!!!!!!!!!" + event.getNewValue());
}
public void afterDestroy(EntryEvent<Integer, User> event) {
System.out.println("afterDestroy!!!!!!!!!" + event);
}
public void afterInvalidate(EntryEvent<Integer, User> event) {
System.out.println("afterInvalidate!!!!!!!!!" + event);
}
public void afterRegionDestroy(RegionEvent<Integer, User> event) {
System.out.println("afterRegionDestroy!!!!!!!!!" + event);
}
public void afterRegionCreate(RegionEvent<Integer, User> event) {
System.out.println("afterRegionCreate!!!!!!!!!" + event);
}
public void afterRegionInvalidate(RegionEvent<Integer, User> event) {
System.out.println("afterRegionInvalidate!!!!!!!!!" + event);
}
public void afterUpdate(EntryEvent<Integer, User> event) {
System.out.println("afterUpdate!!!!!!!!!" + event);
}
public void afterRegionClear(RegionEvent<Integer, User> event) {
System.out.println("afterRegionClear!!!!!!!!!" + event);
}
public void afterRegionLive(RegionEvent<Integer, User> event) {
System.out.println("afterRegionLive!!!!!!!!!" + event);
}
public void close() {
System.out.println("close!!!!!!!!!");
}
}
To create a listener for Region
, create a class that inheritsCacheListener <K, V>
.
Set Key
, Value
of the Region
you want to register as a listener in Key
, Value
.
The following two were verified this time.
-Region
creation event processing: ʻafterRegionCreate method processing is executed -User new registration event processing: ʻafterCreate
method processing is executed
--Next, the implementation that registers the listener in Region
UserRegion.java
package spring.geode.geodeCommon.region;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.Region;
import org.springframework.data.gemfire.ReplicatedRegionFactoryBean;
import spring.geode.geodeCommon.listener.UserRegionListener;
import spring.geode.geodeCommon.model.User;
/**
*Manage users{@link Region}Create settings for
*
*/
public class UserRegion {
public Region<Integer, User> createUserRegion(final GemFireCache cache) {
return cache.<Integer, User>getRegion("Users");
}
public ReplicatedRegionFactoryBean<Integer, User> createUserRegionFactory(GemFireCache cache) {
ReplicatedRegionFactoryBean<Integer, User> replicatedRegionFactory = new ReplicatedRegionFactoryBean<>();
UserRegionListener[] listeners = {new UserRegionListener()};
listeners[0] = new UserRegionListener();
replicatedRegionFactory.setCacheListeners(listeners);
replicatedRegionFactory.setClose(false);
replicatedRegionFactory.setCache(cache);
replicatedRegionFactory.setRegionName("Users");
replicatedRegionFactory.setPersistent(false);
return replicatedRegionFactory;
}
}
Create a Region
that manages the User with the createUserRegion
method and register the bean in the ʻApplicationContext`.
Set to Region
with the createUserRegionFactory
method.
The process of registering the listener created above in Region
is also performed here.
--Implementation to set the Region
and settings implemented above in the app
GeodeClientApplication.java
package spring.geode.client.geodeClient;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.Region;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.gemfire.ReplicatedRegionFactoryBean;
import org.springframework.data.gemfire.config.annotation.PeerCacheApplication;
import org.springframework.data.gemfire.repository.config.EnableGemfireRepositories;
import spring.geode.client.geodeClient.repository.UserRepository;
import spring.geode.geodeCommon.model.User;
import spring.geode.geodeCommon.region.UserRegion;
@SpringBootApplication
@PeerCacheApplication(name = "SpringGeodeClientApplication",locators = "localhost[40404]")
@EnableGemfireRepositories(basePackageClasses = UserRepository.class)
public class GeodeClientApplication {
public static void main(String[] args) {
SpringApplication.run(GeodeClientApplication.class, args);
}
@Configuration
static class CacheInitializer {
@Bean
Region<Integer, User> userRegion(final GemFireCache cache) {
return new UserRegion().createUserRegion(cache);
}
@Bean
public ReplicatedRegionFactoryBean<Integer, User> replicatedRegion(GemFireCache cache) {
return new UserRegion().createUserRegionFactory(cache);
}
}
}
GeodeServerApplication.java
package spring.geode.server.geodeServer;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.Region;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.gemfire.ReplicatedRegionFactoryBean;
import org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions;
import org.springframework.data.gemfire.config.annotation.EnableLocator;
import org.springframework.data.gemfire.config.annotation.EnableManager;
import org.springframework.data.gemfire.config.annotation.PeerCacheApplication;
import org.springframework.data.gemfire.repository.config.EnableGemfireRepositories;
import spring.geode.geodeCommon.model.User;
import spring.geode.geodeCommon.region.UserRegion;
import spring.geode.server.geodeServer.repository.UserRepository;
@SpringBootApplication
@PeerCacheApplication(name = "SpringGeodeServerApplication", locators = "localhost[40404]")
@EnableGemfireRepositories(basePackageClasses = UserRepository.class)
public class GeodeServerApplication {
public static void main(String[] args) {
SpringApplication.run(GeodeServerApplication.class, args);
}
@Configuration
@EnableLocator(port = 40404)
@EnableManager(start = true)
static class LocatorManagerConfiguration {
}
@Configuration
static class CacheInitializer {
@Bean
Region<Integer, User> userRegion(final GemFireCache cache) {
return new UserRegion().createUserRegion(cache);
}
@Bean
public ReplicatedRegionFactoryBean<Integer, User> replicatedRegion(GemFireCache cache) {
return new UserRegion().createUserRegionFactory(cache);
}
}
}
The settings in Region
and Region
are reflected in the processing in the CacheInitializer
class.
Implement this in an app that starts as a cache built-in server.
I named the class Client
and Server
, but this time it starts in P2P format, so I added the @ PeerCacheApplication
annotation to the class.
Don't worry about the class name. ..
This completes the implementation of event processing.
Since the process to start locator
is implemented in GeodeServerApplication.java
, start it from GeodeServerApplication.java
and check the operation.
GeodeServerApplication.Log excerpt at java startup
[info 2019/02/03 02:56:32.334 JST <main> tid=0x1] Initializing region Users
[info 2019/02/03 02:56:32.334 JST <main> tid=0x1] Initialization of region Users completed
afterRegionCreate!!!!!!!!!RegionEventImpl[region=org.apache.geode.internal.cache.DistributedRegion[path='/Users';scope=DISTRIBUTED_NO_ACK';dataPolicy=REPLICATE; concurrencyChecksEnabled];op=REGION_CREATE;isReinitializing=false;callbackArg=null;originRemote=false;originMember=192.168.11.3(SpringGeodeServerApplication:5899)<ec><v0>:1024;tag=null]
[info 2019/02/03 02:56:32.705 JST <main> tid=0x1] Initializing ExecutorService 'applicationTaskExecutor'
org.apache.coyote.AbstractProtocol start
information: Starting ProtocolHandler ["http-nio-9090"]
[info 2019/02/03 02:56:32.877 JST <main> tid=0x1] Tomcat started on port(s): 9090 (http) with context path ''
[info 2019/02/03 02:56:32.880 JST <main> tid=0x1] Started GeodeServerApplication in 3.66 seconds (JVM running for 5.179)
GeodeClientApplication.Log excerpt at java startup
[info 2019/02/03 02:56:49.107 JST <main> tid=0x1] Initializing region Users
[info 2019/02/03 02:56:49.113 JST <main> tid=0x1] Region Users requesting initial image from 192.168.11.3(SpringGeodeServerApplication:5899)<ec><v0>:1024
[info 2019/02/03 02:56:49.116 JST <main> tid=0x1] Users is done getting image from 192.168.11.3(SpringGeodeServerApplication:5899)<ec><v0>:1024. isDeltaGII is false
[info 2019/02/03 02:56:49.116 JST <main> tid=0x1] Initialization of region Users completed
afterRegionCreate!!!!!!!!!RegionEventImpl[region=org.apache.geode.internal.cache.DistributedRegion[path='/Users';scope=DISTRIBUTED_NO_ACK';dataPolicy=REPLICATE; concurrencyChecksEnabled];op=REGION_CREATE;isReinitializing=false;callbackArg=null;originRemote=false;originMember=192.168.11.3(SpringGeodeClientApplication:5901)<v1>:1025;tag=null]
[info 2019/02/03 02:56:49.510 JST <main> tid=0x1] Initializing ExecutorService 'applicationTaskExecutor'
org.apache.coyote.AbstractProtocol start
information: Starting ProtocolHandler ["http-nio-9000"]
[info 2019/02/03 02:56:49.919 JST <main> tid=0x1] Tomcat started on port(s): 9000 (http) with context path ''
[info 2019/02/03 02:56:49.922 JST <main> tid=0x1] Started GeodeClientApplication in 4.245 seconds (JVM running for 5.513)
If you can see the above log in the startup logs of the two apps, the region creation event processing is OK.
Region Users requesting initial image from 192.168.11.3(SpringGeodeServerApplication:5899)<ec><v0>:1024
By the way, in the above log, the Region
named ʻUsers of
GeodeClientApplicationseems to initialize
Region using the image of
Regioncreated by
GeodeServerApplication`.
Next, check if the listener processing is executed when the new user data is registered in the Region
on the GeodeClientApplcaition
side and the data is synchronized with the GeodeServerApplcaition
.
User registration request to GeodeClientApplication
curl -X POST -H "Content-Type: application/json" -d '{"name":"Michel", "age":"100"}' localhost:9000/register/user
Log in GeodeServerApplcaition
after sending a request
GeodeServerApplication.java log excerpt
[info 2019/02/03 04:48:30.587 JST <pool-3-thread-1> tid=0x5b] Initialization of region _monitoringRegion_192.168.11.3<v1>1025 completed
[info 2019/02/03 04:48:30.593 JST <pool-3-thread-1> tid=0x5b] Initializing region _notificationRegion_192.168.11.3<v1>1025
[info 2019/02/03 04:48:30.595 JST <pool-3-thread-1> tid=0x5b] Initialization of region _notificationRegion_192.168.11.3<v1>1025 completed
2019-02-03T04:48:46.176823
afterCreate!!!!!!!!!User(id=-1816523715, name=Michel, age=100)
As expected, the event handling method seems to be firing in GeodeServerApplication
.
The difference between "when data is persisted in GeodeClientApplication
"and" when event processing is executed in GeodeServerApplication
" is taken, and after data is persisted in one cache server, it is persisted in another cache server. I measured the latency until the data synchronization event was executed.
When I repeated the above operation check 10 times with the for statement and took the average latency, the result was 0.002ms
, which was very fast.
It may not be very helpful because the number of trials is small, but I am personally satisfied.
Next, let's implement persistence.
Recommended Posts