03.设计模式之装饰模式设计多级缓存框架&外观模式

课程标题《基于装饰模式手写多级缓存框架》
课程内容:
1.基于装饰模式手写多级缓存框架演示
2.一级与二级缓存基本的概念
3.手写模拟一级与二级缓存基本概念
4.装饰模式基本架构设计原理
5.基于装饰模式重构设计多级缓存
6.什么是外观模式?外观模式重构原理

20点25分准时开始

一级与二级、三级缓存基本的概念

img

jvm缓存(一级缓存)

优点:查询速度非常快

缺点:

1.jvm内置缓存与业务申请内存没有解耦,有可能会发生内存溢出问题

2.缓存容量比较少的

3.jvm内置缓存集群的话 需要考虑数据一致性问题

4.jvm内存缓存 jvm服务器重启时 内存数据都没有了

缓存—当缓存满了 缓存淘汰策略 将近期没有使用的缓存 自动清理掉

jvm内置缓存:EhCache 、OSCache 底层就是一个map集合

触发gc回收时 ,stw 短暂暂停用户线程 会形式短暂卡顿问题

将数据存放在内存—将对象序列化 json

从内存中读取数据到程序中(反序列化 json数据变成对象)

将数据存放在内存、redis(内存)、数据库

redis缓存(二级缓存)

优点:查询数据存放内存中,缓存数据非常多 redis集群

缺点:但是查询过程中 需要经过网络 IO操作

数据库(三级)

优点:存放数据内容比redis更多 更加可靠

缺点:数据直接持久化在硬盘中,查询效率偏低 会经过磁盘io

img

在实际开发项目,为了减少数据库的访问压力,我们都会将数据缓存到内存中,比如:Redis(分布式缓存)、EhCache(JVM内置缓存)。

缓存级别越小缓存内容越少,缓存级别越大缓存内容越多;

例如在早期项目中,项目比较小可能不会使用Redis作为缓存,使用JVM内置的缓存框架,项目比较大的时候开始采用Redis分布式缓存框架,这时候需要设计一级与二级缓存。

缓存机制
JVM内置缓存:将数据缓存到当前JVM中
缺陷:占用当前JVM内存空间,可能造成内存溢出问题;集群很难保证各个节点之间数据同步问题。
举例:EhCache,OsCache底层原理采用HashMap实现 淘汰策略
分布式缓存Redis:数据能够共享

装饰模式概念

不改变原有的代码实现增强。Mybatis、Hibernate二级缓存都属于开发者自己去实现扩展的功能。

装饰模式与代理模式区别

代理模式对目标对象(目标方法)实现增强;

装饰模式对装饰对象实现增强,不能改变原有代码。

基于HashMap手写Jvm内置缓存

package com.mayikt.utils;

import com.alibaba.fastjson.JSONObject;
import com.mayikt.entity.UserEntity;

import java.util.HashMap;

public class JvmMapCacheUtils<V> {

    private static HashMap<String, String> cacheMap = new HashMap<String, String>();

    public static void putEntity(String key, Object object) {
        cacheMap.put(key, JSONObject.toJSONString(object));
    }

    public static <T> T getEntity(String key, Class<T> t) {
        String json = cacheMap.get(key);
        JSONObject jsonObject = JSONObject.parseObject(json);
        return JSONObject.parseObject(json, t);
    }

    public static void main(String[] args) {
        UserEntity userEntity = new UserEntity(1, "mayikt", 22);
        JvmMapCacheUtils.putEntity("user1", userEntity);
        UserEntity user = JvmMapCacheUtils.getEntity("user1", UserEntity.class);
        System.out.println(user);
    }
}

模拟一级与二、三级缓存概念

package com.mayikt.service;

import com.alibaba.fastjson.JSONObject;
import com.mayikt.entity.UserEntity;
import com.mayikt.mapper.UserMapper;
import com.mayikt.utils.JvmMapCacheUtils;
import com.mayikt.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author 余胜军
 * @ClassName MemberService
 * @qq 644064779
 * @addres www.mayikt.com
 * 微信:yushengjun644
 */
@RestController
public class MemberService {
    @Autowired
    private UserMapper userMapper;

    @RequestMapping("/getMember")
    public UserEntity getMember(Integer id) {
        // 1.先查询一级缓存(jvm内置缓存)
        String cacheKey = "com.mayikt.service.MemberService.getMember()Integer=" + id;
        UserEntity jvmUserEntity = JvmMapCacheUtils.getEntity(cacheKey, UserEntity.class);
        if (jvmUserEntity != null) {
            return jvmUserEntity;
        }
        // 2.如果一级缓存没有 在查询 二级缓存(redis)
        String redisJson = RedisUtil.getString(cacheKey);
        if (!StringUtils.isEmpty(redisJson)) {
            UserEntity redisUserEntity = JSONObject.parseObject(redisJson, UserEntity.class);
            JvmMapCacheUtils.putEntity(cacheKey, redisUserEntity);
            return redisUserEntity;
        }
        // 3.如果二级缓存没有在查询数据库(三级缓存)
        UserEntity dbUserEntity = userMapper.findByUser(id);
        if (dbUserEntity == null) {
            return null;
        }
        // 将数据存放二级和三级缓存
        String cacheValue = JSONObject.toJSONString(dbUserEntity);
        RedisUtil.setString(cacheKey, cacheValue);
        JvmMapCacheUtils.putEntity(cacheKey, dbUserEntity);
        return dbUserEntity;
    }
}

装饰模式基本架构设计原理

在不改变原有代码的基础之上,新增附加功能

装饰模式应用场景

多级缓存设计、mybatis中一级与二级缓存、IO流/发送短信

对接短信接口 阿里云?—发送短信挂的情况下?

阿里云—最开始基本功能

腾讯云----额外增强

华为云—额外增强

img

装饰者模式定义
(1)抽象组件:定义一个抽象接口,来规范准备附加功能的类
(2)具体组件:将要被附加功能的类,实现抽象角色接口
(3)抽象装饰者:持有对具体构件角色的引用并定义与抽象构件角色一致的接口
(4)具体装饰:实现抽象装饰者角色,负责对具体构件添加额外功能。

定义早期装饰模式一级缓存

package com.mayikt.decorate;

/**
 * @author 余胜军
 * @ClassName ComponentCache
 * @qq 644064779
 * @addres www.mayikt.com
 * 微信:yushengjun644
 */
public interface ComponentCache {
    <T> T getCache(String key);
}

package com.mayikt.decorate;

import com.mayikt.entity.UserEntity;
import com.mayikt.mapper.UserMapper;
import com.mayikt.utils.JvmMapCacheUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author 余胜军
 * @ClassName JvmComponentCache
 * @qq 644064779
 * @addres www.mayikt.com
 * 微信:yushengjun644
 */
@Component
public class JvmComponentCache implements ComponentCache {
    @Autowired
    private UserMapper userMapper;

    @Override
    public <T> T getCache(String key) {
        //1.先查询一级缓存
        UserEntity jvmUser = JvmMapCacheUtils.getEntity(key, UserEntity.class);
        if (jvmUser != null) {
            return (T) jvmUser;
        }
        //2.查询db
        UserEntity dbUser = userMapper.findByUser(1);
        if (dbUser == null) {
            return null;
        }
        JvmMapCacheUtils.putEntity(key, dbUser);
        return (T) dbUser;
    }
}

基于装饰模式重构设计多级缓存

基本功能

package com.mayikt.decorate;

/**
 * @author 余胜军
 * @ClassName ComponentCache
 * @qq 644064779
 * @addres www.mayikt.com
 * 微信:yushengjun644
 */
public interface ComponentCache {
    <T> T getCache(String key);
}

package com.mayikt.decorate;

import com.mayikt.entity.UserEntity;
import com.mayikt.mapper.UserMapper;
import com.mayikt.utils.JvmMapCacheUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author 余胜军
 * @ClassName JvmComponentCache
 * @qq 644064779
 * @addres www.mayikt.com
 * 微信:yushengjun644
 */
@Component
public class JvmComponentCache implements ComponentCache {
    @Autowired
    private UserMapper userMapper;

    @Override
    public <T> T getCache(String key) {
        //1.先查询一级缓存
        UserEntity jvmUser = JvmMapCacheUtils.getEntity(key, UserEntity.class);
        if (jvmUser == null) {
            return null;
        }
        return (T) jvmUser;
    }
}

装饰模式重构

这里查询db中的参数是暂时写死的,主要体现多级缓存实现思路。

package com.mayikt.decorate;

/**
 * @author 余胜军
 * @ClassName AbstractDecorate
 * @qq 644064779
 * @addres www.mayikt.com
 * 微信:yushengjun644
 */
public interface AbstractDecorate extends ComponentCache {
}
package com.mayikt.decorate;

import com.alibaba.fastjson.JSONObject;
import com.mayikt.entity.UserEntity;
import com.mayikt.utils.JvmMapCacheUtils;
import com.mayikt.utils.RedisUtil;
import org.apache.catalina.User;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

/**
 * @author 余胜军
 * @ClassName RedisDecorate
 * @qq 644064779
 * @addres www.mayikt.com
 * 微信:yushengjun644
 */
@Component
public class RedisDecorate extends JvmComponentCache implements AbstractDecorate {
    @Override
    public <T> T getCache(String key) {
        // 先查询一级缓存
        UserEntity jvmUserEntity = super.getCache(key);
        if (jvmUserEntity != null) {
            return (T) jvmUserEntity;
        }
        // 一级缓存中没有该数据查询二级缓存
        String redisJson = RedisUtil.getString(key);
        if (StringUtils.isEmpty(redisJson)) {
            return null;
        }
        UserEntity redisUserEntity = JSONObject.parseObject(redisJson, UserEntity.class);
        JvmMapCacheUtils.putEntity(key, redisUserEntity);
        return (T) redisUserEntity;
    }
}

package com.mayikt.decorate;

import com.alibaba.fastjson.JSONObject;
import com.mayikt.entity.UserEntity;
import com.mayikt.mapper.UserMapper;
import com.mayikt.utils.JvmMapCacheUtils;
import com.mayikt.utils.RedisUtil;
import org.apache.catalina.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author 余胜军
 * @ClassName MySQLDecorate
 * @qq 644064779
 * @addres www.mayikt.com
 * 微信:yushengjun644
 */
@Component
public class MySQLDecorate extends RedisDecorate implements AbstractDecorate {
    @Autowired
    private UserMapper userMapper;

    @Override
    public <T> T getCache(String key) {
        UserEntity redisUserEntity = super.getCache(key);
        if (redisUserEntity != null) {
            return (T) redisUserEntity;
        }
        UserEntity dbUser = userMapper.findByUser(1);
        if (dbUser == null) {
            return null;
        }
        // 将db中数据写入二级和一级缓存中
        RedisUtil.setString(key, JSONObject.toJSONString(dbUser));
        JvmMapCacheUtils.putEntity(key, dbUser);
        return (T) dbUser;
    }
}

代码

📎mayikt-designmode.rar

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陌陌龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值