转载自:
http://www.onlinetechvision.com/?p=425
This article shows how to distribute Spring beans by using Coherence. In below sample application, a new cluster named OTV has been created and a spring bean has been distributed by using a cache object named user-map. It has been distributed between two members of the cluster.
Used Technologies :
JDK 1.6.0_21
Spring 3.0.5
Maven 3.0.2
Coherence 3.7.0
SolarisOS 5.10
STEP 1 : CREATE MAVEN PROJECT
A maven project is created as below. (It can be created by using Maven or IDE Plug-in).
STEP 2 : DOWNLOAD COHERENCE PACKAGE
Coherence package is downloaded via http://www.oracle.com/technetwork/middleware/coherence/downloads/index.html
STEP 3 : LIBRARIES
Firstly, Spring dependencies are added to Maven’ s pom.xml.
1
2
3
4
5
6
7
8
9
10
11
|
<!-- Spring 3 dependencies -->
<
dependency
>
<
groupId
>org.springframework</
groupId
>
<
artifactId
>spring-core</
artifactId
>
<
version
>${spring.version}</
version
>
</
dependency
>
<
dependency
>
<
groupId
>org.springframework</
groupId
>
<
artifactId
>spring-context</
artifactId
>
<
version
>${spring.version}</
version
>
</
dependency
>
|
Coherence library is installed to Local Maven Repository and its description is added to pom.xml as below. Also if maven is not used, coherence.jar file can be added to classpath.
1
2
3
4
5
6
|
<!-- Coherence library(from local repository) -->
<
dependency
>
<
groupId
>com.tangosol</
groupId
>
<
artifactId
>coherence</
artifactId
>
<
version
>3.7.0</
version
>
</
dependency
>
|
For creating runnable-jar, below plugin can be used.
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
|
<
plugin
>
<
groupId
>org.apache.maven.plugins</
groupId
>
<
artifactId
>maven-shade-plugin</
artifactId
>
<
version
>1.3.1</
version
>
<
executions
>
<
execution
>
<
phase
>package</
phase
>
<
goals
>
<
goal
>shade</
goal
>
</
goals
>
<
configuration
>
<
transformers
>
<
transformer
implementation
=
"org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"
>
<
mainClass
>com.otv.exe.Application</
mainClass
>
</
transformer
>
<
transformer
implementation
=
"org.apache.maven.plugins.shade.resource.AppendingTransformer"
>
<
resource
>META-INF/spring.handlers</
resource
>
</
transformer
>
<
transformer
implementation
=
"org.apache.maven.plugins.shade.resource.AppendingTransformer"
>
<
resource
>META-INF/spring.schemas</
resource
>
</
transformer
>
</
transformers
>
</
configuration
>
</
execution
>
</
executions
>
</
plugin
>
|
STEP 4 : CREATE otv-coherence-cache-config.xml
otv-coherence-cache-config.xml contains caching-schemes(distributed or replicated) and caching-scheme-mapping configuration. Created cache configuration should be added to coherence-cache-config.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
|
<?
xml
version
=
"1.0"
?>
<
cache-config
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns
=
"http://xmlns.oracle.com/coherence/coherence-cache-config"
xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config
coherence-cache-config.xsd">
<
caching-scheme-mapping
>
<
cache-mapping
>
<
cache-name
>user-map</
cache-name
>
<
scheme-name
>MapDistCache</
scheme-name
>
</
cache-mapping
>
</
caching-scheme-mapping
>
<
caching-schemes
>
<
distributed-scheme
>
<
scheme-name
>MapDistCache</
scheme-name
>
<
service-name
>MapDistCache</
service-name
>
<
backing-map-scheme
>
<
local-scheme
>
<
unit-calculator
>BINARY</
unit-calculator
>
</
local-scheme
>
</
backing-map-scheme
>
<
autostart
>true</
autostart
>
</
distributed-scheme
>
</
caching-schemes
>
</
cache-config
>
|
STEP 5 : CREATE tangosol-coherence-override.xml
tangosol-coherence-override.xml contains cluster, member-identity and configurable-cache-factory configuration. Also below configuration xml file show first member of the cluster.
tangosol-coherence-override.xml for first member of the cluster :
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
|
<?
xml
version
=
'1.0'
?>
<
coherence
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns
=
"http://xmlns.oracle.com/coherence/coherence-operational-config"
xsi:schemaLocation
=
"http://xmlns.oracle.com/coherence/coherence-operational-config coherence-operational-config.xsd"
>
<
cluster-config
>
<
member-identity
>
<
cluster-name
>OTV</
cluster-name
>
<!-- Name of the first member of the cluster -->
<
role-name
>OTV1</
role-name
>
</
member-identity
>
<
unicast-listener
>
<
well-known-addresses
>
<
socket-address
id
=
"1"
>
<!-- IP Address of the first member of the cluster -->
<
address
>x.x.x.x</
address
>
<
port
>8089</
port
>
</
socket-address
>
<
socket-address
id
=
"2"
>
<!-- IP Address of the second member of the cluster -->
<
address
>y.y.y.y</
address
>
<
port
>8089</
port
>
</
socket-address
>
</
well-known-addresses
>
<!-- Name of the first member of the cluster -->
<
machine-id
>OTV1</
machine-id
>
<!-- IP Address of the first member of the cluster -->
<
address
>x.x.x.x</
address
>
<
port
>8089</
port
>
<
port-auto-adjust
>true</
port-auto-adjust
>
</
unicast-listener
>
</
cluster-config
>
<
configurable-cache-factory-config
>
<
init-params
>
<
init-param
>
<
param-type
>java.lang.String</
param-type
>
<
param-value
system-property
=
"tangosol.coherence.cacheconfig"
>
otv-coherence-cache-config.xml
</
param-value
>
</
init-param
>
</
init-params
>
</
configurable-cache-factory-config
>
</
coherence
>
|
tangosol-coherence-override.xml for second member of the cluster :
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
|
<?
xml
version
=
'1.0'
?>
<
coherence
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns
=
"http://xmlns.oracle.com/coherence/coherence-operational-config"
xsi:schemaLocation
=
"http://xmlns.oracle.com/coherence/coherence-operational-config coherence-operational-config.xsd"
>
<
cluster-config
>
<
member-identity
>
<
cluster-name
>OTV</
cluster-name
>
<!-- Name of the second member of the cluster -->
<
role-name
>OTV2</
role-name
>
</
member-identity
>
<
unicast-listener
>
<
well-known-addresses
>
<
socket-address
id
=
"1"
>
<!-- IP Address of the first member of the cluster -->
<
address
>x.x.x.x</
address
>
<
port
>8089</
port
>
</
socket-address
>
<
socket-address
id
=
"2"
>
<!-- IP Address of the second member of the cluster -->
<
address
>y.y.y.y</
address
>
<
port
>8089</
port
>
</
socket-address
>
</
well-known-addresses
>
<!-- Name of the second member of the cluster -->
<
machine-id
>OTV2</
machine-id
>
<!-- IP Address of the second member of the cluster -->
<
address
>y.y.y.y</
address
>
<
port
>8089</
port
>
<
port-auto-adjust
>true</
port-auto-adjust
>
</
unicast-listener
>
</
cluster-config
>
<
configurable-cache-factory-config
>
<
init-params
>
<
init-param
>
<
param-type
>java.lang.String</
param-type
>
<
param-value
system-property
=
"tangosol.coherence.cacheconfig"
>
otv-coherence-cache-config.xml</
param-value
>
</
init-param
>
</
init-params
>
</
configurable-cache-factory-config
>
</
coherence
>
|
STEP 6 : CREATE applicationContext.xml
applicationContext.xml is created.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<
beans
xmlns
=
"http://www.springframework.org/schema/beans"
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- Beans Declaration -->
<
bean
id
=
"User"
class
=
"com.otv.user.User"
></
bean
>
<
bean
id
=
"CacheService"
class
=
"com.otv.srv.CacheService"
></
bean
>
<
bean
id
=
"CacheUpdater"
class
=
"com.otv.exe.CacheUpdater"
>
<
property
name
=
"user"
ref
=
"User"
/>
<
property
name
=
"cacheService"
ref
=
"CacheService"
/>
</
bean
>
</
beans
>
|
STEP 7 : CREATE SPRING BEAN
A new User Spring bean is created. This bean will be distributed between two node in OTV cluster. For serializing,java.io.Serializable interface has been implemented but PortableObject can be implemented for better performance.
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
|
package
com.otv.user;
import
java.io.Serializable;
/**
* @author onlinetechvision.com
* @since 15 Oct 2011
* @version 1.0.0
*
*/
public
class
User
implements
Serializable {
private
static
final
long
serialVersionUID = 1L;
private
String name;
private
String surname;
public
User(String name, String surname) {
this
.name = name;
this
.surname = surname;
}
public
String getName() {
return
name;
}
public
void
setName(String name) {
this
.name = name;
}
public
String getSurname() {
return
surname;
}
public
void
setSurname(String surname) {
this
.surname = surname;
}
@Override
public
String toString() {
StringBuffer strBuff =
new
StringBuffer();
strBuff.append(
"name : "
).append(name);
strBuff.append(
", surname : "
).append(surname);
return
strBuff.toString();
}
}
|
STEP 8 : CREATE ICacheService INTERFACE
A new ICacheService Interface is created for service layer.
1
2
3
4
5
6
7
8
9
10
11
|
package
com.otv.srv;
import
com.tangosol.net.NamedCache;
public
interface
ICacheService {
public
NamedCache getCache();
public
void
addToCache(Object key, Object value);
public
void
deleteFromCache(Object key);
}
|
STEP 9 : CREATE CacheService
CacheService is created for service layer by implementing ICacheService.
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
|
package
com.otv.srv;
import
org.apache.log4j.Logger;
import
com.otv.listener.UserMapListener;
import
com.tangosol.net.CacheFactory;
import
com.tangosol.net.NamedCache;
/**
* @author onlinetechvision.com
* @since 15 Oct 2011
* @version 1.0.0
*
*/
public
class
CacheService
implements
ICacheService {
private
static
Logger log = Logger.getLogger(CacheService.
class
);
private
NamedCache cache =
null
;
private
static
final
String USER_MAP =
"user-map"
;
private
static
final
long
LOCK_TIMEOUT = -
1
;
public
CacheService() {
cache = CacheFactory.getCache(USER_MAP);
cache.addMapListener(
new
UserMapListener());
}
public
NamedCache getCache() {
return
cache;
}
public
void
setCache(NamedCache cache) {
this
.cache = cache;
}
public
void
addToCache(Object key, Object value) {
// key is locked
cache.lock(key, LOCK_TIMEOUT);
try
{
// application logic
cache.put(key, value);
}
finally
{
// key is unlocked
cache.unlock(key);
}
}
public
void
deleteFromCache(Object key) {
// key is locked
cache.lock(key, LOCK_TIMEOUT);
try
{
// application logic
cache.remove(key);
}
finally
{
// key is unlocked
cache.unlock(key);
}
}
}
|
STEP 10 : CREATE USERMAPLISTENER IMPL CLASS
A new UserMapListener class is created. This listener receives distributed user-map events.
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
|
package
com.otv.listener;
import
org.apache.log4j.Logger;
import
com.tangosol.util.MapEvent;
import
com.tangosol.util.MapListener;
/**
* @author onlinetechvision.com
* @since 15 Oct 2011
* @version 1.0.0
*
*/
public
class
UserMapListener
implements
MapListener {
private
static
Logger logger = Logger.getLogger(UserMapListener.
class
);
public
void
entryDeleted(MapEvent me) {
logger.debug(
"Deleted Key = "
+ me.getKey() +
", Value = "
+ me.getOldValue());
}
public
void
entryInserted(MapEvent me) {
logger.debug(
"Inserted Key = "
+ me.getKey() +
", Value = "
+ me.getNewValue());
}
public
void
entryUpdated(MapEvent me) {
// logger.debug("Updated Key = " + me.getKey() + ", New_Value = " + me.getNewValue() + ", Old Value = " + me.getOldValue());
}
}
|
STEP 11 : CREATE CacheUpdater
CacheUpdater Class is created to add new entry to cache and monitor cache content.
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
|
package
com.otv.exe;
import
java.util.Collection;
import
org.apache.log4j.Logger;
import
com.otv.srv.ICacheService;
import
com.otv.user.User;
/**
* @author onlinetechvision.com
* @since 15 Oct 2011
* @version 1.0.0
*
*/
public
class
CacheUpdater
implements
Runnable {
private
static
Logger log = Logger.getLogger(CacheUpdater.
class
);
ICacheService cacheService;
User user;
public
User getUser() {
return
user;
}
public
void
setUser(User user) {
this
.user = user;
}
public
ICacheService getCacheService() {
return
cacheService;
}
public
void
setCacheService(ICacheService cacheService) {
this
.cacheService = cacheService;
}
public
void
run() {
//New User are created...
//Entries which will be inserted via first member of the cluster so before the project is built
// in order to deploy first member of the cluster, this code block should be opened...
getUser().setName(
"Bruce"
);
getUser().setSurname(
"Willis"
);
//Entries are added to cache...
getCacheService().addToCache(
"user1"
, getUser());
// //New User are created...
// //Entries which will be inserted via second member of the cluster so before the project is built
// // in order to deploy second member of the cluster, this code block should be opened...
// getUser().setName("Clint");
// getUser().setSurname("Eastwood");
//
// //Entries are added to cache...
// getCacheService().addToCache("user2", getUser());
//Cache Entries are printed...
printCacheEntries();
}
private
void
printCacheEntries() {
Collection<User> userCollection =
null
;
try
{
while
(
true
) {
userCollection = (Collection<User>)getCacheService().getCache().values();
for
(User user : userCollection) {
log.debug(
"Cache Content : "
+user);
}
Thread.sleep(
10000
);
}
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
|
STEP 12 : CREATE Application
Application Class is created to run the application.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
package
com.otv.exe;
import
org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author onlinetechvision.com
* @since 15 Oct 2011
* @version 1.0.0
*
*/
public
class
Application {
public
static
void
main(String[] args) {
ApplicationContext context =
new
ClassPathXmlApplicationContext(
"applicationContext.xml"
);
CacheUpdater cacheUpdater = (CacheUpdater) context.getBean(
"CacheUpdater"
);
cacheUpdater.run();
}
}
|
STEP 13 : BUILD PROJECT
After OTV_Spring_Coherence Project is build, OTV_Spring_Coherence-0.0.1-SNAPSHOT.jar will be created.
Important Note : Members of the cluster have got different configurations for Coherence so the project should be built separately for each member.
STEP 14 : RUN PROJECT ON FIRST MEMBER OF THE CLUSTER
After created OTV_Spring_Coherence-0.0.1-SNAPSHOT.jar file is run at the members of the cluster, below output logs will be shown on first member’ s console:
1
2
3
4
5
6
7
8
9
10
|
--A new cluster is created and First Member joins the cluster and adds a new entry to the cache.
15.10.2011 00:52:48 DEBUG (UserMapListener.java:23) - Inserted Key = user1, Value = name : Bruce, surname : Willis
15.10.2011 00:52:48 DEBUG (CacheUpdater.java:51) - Cache Content : name : Bruce, surname : Willis
.......
--Second Member joins the cluster and adds a new entry to the cache.
15.10.2011 00:53:13 DEBUG (UserMapListener.java:23) - Inserted Key = user2, Value = name : Clint, surname : Eastwood
.......
--After second member adds a new entry, cache content is shown as below :
15.10.2011 00:53:19 DEBUG (CacheUpdater.java:51) - Cache Content : name : Clint, surname : Eastwood
15.10.2011 00:53:19 DEBUG (CacheUpdater.java:51) - Cache Content : name : Bruce, surname : Willis
|
Second member’ s console :
1
2
3
4
|
--After Second Member joins the cluster and adds a new entry to the cache, cache content is shown as below and the members has got same entries :.
15.10.2011 00:53:13 DEBUG (UserMapListener.java:23) - Inserted Key = user2, Value = name : Clint, surname : Eastwood
15.10.2011 00:53:14 DEBUG (CacheUpdater.java:51) - Cache Content : name : Bruce, surname : Willis
15.10.2011 00:53:15 DEBUG (CacheUpdater.java:51) - Cache Content : name : Clint, surname : Eastwood
|
STEP 15 : DOWNLOAD