Springboot使用J2Cache,整合ehcache和redis緩存框架,實現兩級緩存

首先看下整合過程
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;
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章