首先看下整合過程
1、pom.xml添加相關依賴
<!-- 添加ehcache支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- Ehcache 座標 -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.4</version>
</dependency>
<!--整合redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<!--整合j2cache-->
<dependency>
<groupId>net.oschina.j2cache</groupId>
<artifactId>j2cache-spring-boot2-starter</artifactId>
<version>2.7.6-release</version>
</dependency>
<dependency>
<groupId>net.oschina.j2cache</groupId>
<artifactId>j2cache-core</artifactId>
<version>2.7.7-release</version>
</dependency>
2、application.yml添加配置
server:
port: 8778
spring:
application:
name: website
cache:
ehcache:
config: classpath:/ehcache.xml
j2cache:
config-location: classpath:/j2cache.properties
cache-clean-mode: active
open-spring-cache: true
3、resources添加ehcache.xml和j2cache.properties配置文件
ehcache.xml內容
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<!--設置磁盤存儲路徑-->
<diskStore path="D:\\ehcache\\"/>
<defaultCache
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
overflowToDisk="true">
</defaultCache>
<cache name="Euser"
eternal="false"
maxEntriesLocalHeap="2000"
timeToIdleSeconds="2000"
timeToLiveSeconds="2000"
maxElementsInMemory="10000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
overflowToDisk="true" >
</cache>
</ehcache>
j2cache.properties內容
#J2Cache configuration
#j2cache 源碼地址https://gitee.com/ld/J2Cache
#########################################
# Cache Broadcast Method
# values:
# jgroups -> use jgroups's multicast
# redis -> use redis publish/subscribe mechanism
#########################################
#廣播策略
#j2cache.broadcast = net.oschina.j2cache.cache.support.redis.SpringRedisPubSubPolicy
j2cache.broadcast = redis
# 是否開啓二級緩存
j2cache.l2-cache-open=true
j2cache.open-spring-cache= true
j2cache.allow-null-values= true
j2cache.cache-clean-mode= active
j2cache.redis-client=jedis
#組播的通道名稱
jgroups.channel.name = j2cache
#########################################
# Level 1&2 provider
# values:
# none -> disable this level cache
# ehcache -> use ehcache2 as level 1 cache
# ehcache3 -> use ehcache3 as level 1 cache
# caffeine -> use caffeine as level 1 cache(only in memory)
# redis -> use redis(hashs) as level 2 cache
# [classname] -> use custom provider
#########################################
#一級緩存使用ehcache3
j2cache.L1.provider_class = ehcache
#j2cache.L2.provider_class = net.oschina.j2cache.cache.support.redis.SpringRedisProvider
j2cache.L2.provider_class = redis
#二級緩存使用redis
#j2cache.L2.provider_class = redis
j2cache.L2.config_section = redis
#########################################
# Cache Serialization Provider
# values:
# fst -> fast-serialization
# kyro -> kyro
# java -> java standard
# [classname implements Serializer]
#########################################
j2cache.serialization = fst
#########################################
# Ehcache configuration
#########################################
#ehcache.name=
ehcache.configXml=/ehcache.xml
#ehcache3.configXml = /ehcache.xml
#########################################
# Caffeine configuration
# caffeine.region.[name] = size, xxxx[s|m|h|d]
#
#########################################
caffeine.region.default = 1000, 1h
#########################################
# Redis connection configuration
#########################################
#########################################
# Redis Cluster Mode
#
# single -> single redis server
# sentinel -> master-slaves servers
# cluster -> cluster servers (數據庫配置無效,使用 database = 0)
# sharded -> sharded servers (密碼、數據庫必須在 hosts 中指定,且連接池配置無效 ; redis://user:[email protected]:6379/0)
#
#########################################
#redis.mode = sentinel
redis.mode = single
#cluster name just for sharded
redis.cluster_name = mymaster
## redis cache namespace optional, default[j2cache]
redis.namespace = j2cache
## connection
#redis.hosts = 127.0.0.1:26378,127.0.0.1:26379,127.0.0.1:26380
redis.hosts = 127.0.0.1:6379
redis.timeout = 2000
redis.password = 123456
redis.database = 0
## redis pub/sub channel name
redis.channel = j2cache
## redis pool properties
redis.maxTotal = -1
redis.maxIdle = 2000
redis.maxWaitMillis = 100
redis.minEvictableIdleTimeMillis = 864000000
redis.minIdle = 1000
redis.numTestsPerEvictionRun = 10
redis.lifo = false
redis.softMinEvictableIdleTimeMillis = 10
redis.testOnBorrow = true
redis.testOnReturn = false
redis.testWhileIdle = false
redis.timeBetweenEvictionRunsMillis = 300000
redis.blockWhenExhausted = true
4、增刪改查demo測試
package com.example.website.controller;
import com.example.website.service.J2cacheService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @author
* @date 2019/6/27 0027
*/
@RestController
@RequestMapping("/index")
public class IndexController {
@Autowired
J2cacheService j2cacheService;
@RequestMapping("/j2cache")
public String j2cache(@RequestParam("key")String key,@RequestParam("value")String value){
return j2cacheService.addCache(key,value);
}
@RequestMapping("/queryCache")
public String queryRedis(@RequestParam("type")String type){
return j2cacheService.queryCache(type);
}
@RequestMapping("/getKey")
public String getKey(@RequestParam("key")String key){
return j2cacheService.getKey(key);
}
@RequestMapping("/deleteKey")
public String deleteKey(@RequestParam("key")String key){
return j2cacheService.deleteKey(key);
}
}
package com.example.website.service;
/**
* @author
* @date 2019/6/28 0028
*/
public interface J2cacheService {
public String addCache(String key,String value);
public String queryCache(String type);
public String getKey(String key);
public String deleteKey(String key);
}
package com.example.website.service.impl;
import com.example.website.service.J2cacheService;
import net.oschina.j2cache.CacheChannel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collection;
/**
* @author
* @date 2019/6/28 0028
*/
@Service
public class J2cacheServiceImpl implements J2cacheService {
@Autowired
CacheChannel cacheChannel;
@Override
public String addCache(String key,String value) {
cacheChannel.set("Euser",key,value);
return "region:Euser,key:"+key+",value:"+value;
}
@Override
public String queryCache(String type) {
StringBuilder sb = new StringBuilder();
if("1".equals(type)){
System.out.println("ehcache緩存==================");
//CacheProvider l1 = cacheChannel.getL1Provider();
Collection<String> keys = cacheChannel.keys("Euser");
for(String key : keys){
sb.append("key:"+key+",value:"+cacheChannel.get("Euser",key));
}
}else if("2".equals(type)){
System.out.println("redis二級緩存================");
//CacheProvider l2 = cacheChannel.getL2Provider();
Collection<String> keys = cacheChannel.keys("Euser");
for(String key : keys){
sb.append("key:"+key+",value:"+cacheChannel.get("Euser",key));
}
}
return sb.toString();
}
@Override
public String getKey(String key) {
Object v = cacheChannel.get("Euser",key);
if(v != null){
return v.toString();
}
return "null";
}
@Override
public String deleteKey(String key) {
cacheChannel.evict("Euser",key);
return "success";
}
}
redis數據
本地D盤會根據設置的目錄,存儲ehcache數據
增加
刪除
key:4 已被刪除
修改
修改跟增加是一樣的,它會覆蓋原有的key值對應的value
查詢
cacheChannel.set("Euser",key,value);
J2Cache set key和value,會直接存入L1和L2。當我們重啓服務器的時候,L1 ehcache被清空,L2 redis數據存在,這個時候,我們去遍歷數據,跟蹤源碼,我們會發現請求去L1取不到數據,這個時候就會去L2取數據,取到數據就會再次放入L1,下次查詢就不需要去L2查詢了,直接從L1獲取數據。
CacheObject obj = new CacheObject(region, key, (byte)1);
obj.setValue(this.holder.getLevel1Cache(region).get(key));//先從L1查詢
if (obj.rawValue() != null) {
return obj;//L1查詢到對象就返回
} else {
String lock_key = key + '%' + region;
synchronized(_g_keyLocks.computeIfAbsent(lock_key, (v) -> {
return new Object();
})) {
obj.setValue(this.holder.getLevel1Cache(region).get(key));//從L1查詢
if (obj.rawValue() != null) {
return obj;
} else {
try {//L1查詢不到數據,從L2查詢
obj.setLevel((byte)2);
obj.setValue(this.holder.getLevel2Cache(region).get(key));
if (obj.rawValue() != null) {
this.holder.getLevel1Cache(region).put(key, obj.rawValue());//並且從L1查詢到數據並放入L2
} else {
boolean cacheNull = cacheNullObject.length > 0 ? cacheNullObject[0] : this.defaultCacheNullObject;
if (cacheNull) {
this.set(region, key, this.newNullObject(), true);
}
}
} finally {
_g_keyLocks.remove(lock_key);
}
return obj;
}
}
}