Ehcache failure when deploying multiple war services in Tomcat

1. Scenario Description

Scenario 1: The same war is copied and deployed to the same Tomcat to run in multiple copies. At this time, the name of the cacheManager is the same (modify the war name for multi-version deployment: ROOT.war, v1.war, v2.war)

Scenario 2: Multiple different wars are deployed to the same Tomcat to run, and the cacheManager names appear the same in multiple wars

illustrate:

1) Scenario 1 is encountered in the Pharmacist 360 drug instruction project, and multiple versions are deployed in the same Tomcat

2) In order to solve the Ehcache failure problem of multiple war services in Tomcat, the RMI cache cluster sharing is not within the scope of this document

 

Second, the solution process

An exception occurs when the Tomcat service starts (only one war service is normal):

Invocation of init method failed; nested exception is net.sf.ehcache.CacheException: Another CacheManager with same name 'drug-instruction' already exists in the same VM. 
Please provide unique names for each CacheManager in the config or do one of following:
1. Use one of the CacheManager.create() static factory methods to reuse same CacheManager with same name or create one if necessary
2. Shutdown the earlier cacheManager before creating new one with same name.

Reason: Ehcache is an in-process cache, and the in-process cache is shared. At this time, add the cache configuration in ehcache.xml: "p:shared="true" , ​​as follows:

<bean id="appCacheManageBean" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
p:configLocation="classpath:spring/drug-instruction-ehcache.xml" p:shared="true" />

 

After modification, redeploying and starting Tomcat can start normally at this time, but when the requested service uses the cache, it fails again (the first A service is normal, and the other B fails), as follows:

java.lang.ClassCastException: com.oncloudit.drug.instruction.dto.Hospital cannot be cast to com.oncloudit.drug.instruction.dto.Hospital

Analysis: First access the A service and cache the object in the Ehcache cache. The B service requests the cache to change the object (only this object belongs to A), but the conversion fails;

It is estimated that different war services of Tomcat have different contexts and corresponding memory areas, but Ehcache is an in-process cache sharing, so the value can be obtained, but the type conversion fails.

 

Solution 1: Serialize and deserialize the cached object and use it, or: Hospital hospital = JsonUtil.json2Object(JsonUtil.object2Json(hospital), new TypeReference<Hospital>() {});

Solution 2: Because the cacheManager names in the two wars A and B are the same, you can dynamically create caches with different names or dynamically generate cache-keys. Here is an example of dynamically generating cache-keys:

Step 1) Define global variables in the two programs A and B

public static final String APP_UNIQUE_IDENTIFIER = UUID.randomUUID().toString();

Step 2) Different projects have different cache-key prefixes

public static final String CACHE_KEY_HOSPITAL = ConfigConstant.APP_UNIQUE_IDENTIFIER + "_hospital";

The cache key is used in this way, so that the cacheManager name in different war services can be the same, and different war projects can work normally

Solution 3: Do not use Ehcache (use memcache, redis...) or deploy war to different Tomcat services

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326702591&siteId=291194637