æç« ç®å½
- ââä¸ãè£ é¥°æ¨¡å¼ââ
- ââ1. å顾å¤çº§ç¼ååºæ¬æ¦å¿µââ
- ââ2. è£ é¥°æ¨¡å¼åºæ¬çæ¦å¿µââ
- ââ3. è£ é¥°æ¨¡å¼åºç¨åºæ¯ââ
- ââ4. è£ é¥°è 模å¼å®ä¹ââ
- ââ5. åºäºMapæåJvmå ç½®ç¼åââ
- ââäºãæåä¸çº§ä¸äºçº§ç¼åââ
- ââ2.1. rediså·¥å ·ç±»ââ
- ââ2.2. å®ä½ç±»ââ
- ââ2.3. æ¥å£ââ
- ââ2.4. æ°æ®åºèæ¬ââ
- ââ2.5. æµè¯æ¡ä¾ââ
- ââ2.6. æµè¯ææå享ââ
- ââä¸ã设计å¤çº§ç¼åæ¡æ¶ââ
- ââ3.1. ç¼å容å¨æ½è±¡ââ
- ââ3.2. ä¸çº§jvmç¼åââ
- ââ3.3. äºçº§ç¼åæ½è±¡æ¥å£ââ
- ââ3.4. æ°å¢äºçº§ç¼åââ
- ââ3.5. Aopä¸èªå®ä¹æ³¨è§£ââ
- ââ3.6. å®ç°äºçº§ç¼åæ¥è¯¢aopæ¦æªââ
- ââ3.7. äºçº§ç¼åå¤å£³å°è£ ââ
- ââ3.8. ç¼å容å¨æ½è±¡ââ
- ââ3.9. 请æ±æµç¨é¾è·¯ââ
- ââ3.10. å¼æºé¡¹ç®ââ
åºäºè£ 饰模å¼è®¾è®¡å¤çº§ç¼å
ä¸ãè£ é¥°æ¨¡å¼
1. å顾å¤çº§ç¼ååºæ¬æ¦å¿µ
å¨å®é å¼å项ç®ï¼ä¸ºäºåå°æ°æ®åºç访é®ååï¼æ们é½ä¼å°æ°æ®ç¼åå°å åä¸
æ¯å¦ï¼Redis(åå¸å¼ç¼å)ãEHCHEï¼JVMå ç½®ç¼åï¼.
ä¾å¦å¨æ©èµ·ä¸ï¼é¡¹ç®æ¯è¾å°å¯è½ä¸ä¼ä½¿ç¨Rediså为ç¼åï¼ä½¿ç¨JVMå ç½®çç¼åæ¡æ¶ï¼
项ç®æ¯è¾å¤§çæ¶åå¼å§éç¨Redisåå¸å¼ç¼åæ¡æ¶ï¼è¿æ¶åéè¦è®¾è®¡ä¸çº§ä¸äºçº§ç¼åã
2. è£ é¥°æ¨¡å¼åºæ¬çæ¦å¿µ
ä¸æ¹ååæ代ç çåºç¡ä¹ä¸ï¼æ°å¢éå åè½
3. è£ é¥°æ¨¡å¼åºç¨åºæ¯
å¤çº§ç¼å设计ãmybatisä¸ä¸çº§ä¸äºçº§ç¼åãIOæµ
4. è£ é¥°è 模å¼å®ä¹
ï¼1ï¼æ½è±¡ç»ä»¶:å®ä¹ä¸ä¸ªæ½è±¡æ¥å£ï¼æ¥è§èåå¤éå åè½çç±»
ï¼2ï¼å ·ä½ç»ä»¶ï¼å°è¦è¢«éå åè½çç±»ï¼å®ç°æ½è±¡æ件è§è²æ¥å£
ï¼3ï¼æ½è±¡è£ 饰è ï¼ææå¯¹å ·ä½æ件è§è²çå¼ç¨å¹¶å®ä¹ä¸æ½è±¡æ件è§è²ä¸è´çæ¥å£
ï¼4ï¼å ·ä½è£ 饰ï¼å®ç°æ½è±¡è£ 饰è è§è²ï¼è´è´£å¯¹å ·ä½æ件添å é¢å¤åè½ã
5. åºäºMapæåJvmå ç½®ç¼å
package com.gblfy.utils;
import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* åºäºMapæåJvmå
ç½®ç¼å
*
* @Author gblfy
* @Date 2022-03-15 21:01
**/
@Component
public class JvmMapCacheUtils {
/**
* 并åç¼å容å¨
*/
private static Map<String, String> cacheList = new ConcurrentHashMap<String, String>();
/**
* ä»æ¬å°ç¼åä¸æ ¹æ®keyè·åå¼
*
* @param key ç¼åkey
* @param t è¿å对象类å
* @param <T> è¿å对象
* @return
*/
public static <T> T getCache(String key, Class<T> t) {
// ç¼ååå¨å¯¹è±¡
String jsonValue = cacheList.get(key);
return JSONObject.parseObject(jsonValue, t);
}
/**
* ç¼åæ°æ®å°æ¬å°jvmä¸
*
* @param key
* @param val
*/
public static void putCache(String key, Object val) {
String jsonValue = JSONObject.toJSONString(val);
cacheList.put(key, jsonValue);
}
/**
* æ ¹æ®ç¼åkeyå é¤æå®ç¼åæ°æ®
*
* @param cacheKey
*/
public static void removeCacheCacheKey(String cacheKey) {
cacheList.remove(cacheKey);
}
/**
* æ´æ°ç¼åæ°æ®
*
* @param key
* @param val
*/
public static void updateCacheByCacheKey(String key, Object val) {
String jsonValue = JSONObject.toJSONString(val);
cacheList.put(key, jsonValue);
}
}
äºãæåä¸çº§ä¸äºçº§ç¼å
2.1. rediså·¥å ·ç±»
package com.gblfy.utils;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* rediså·¥å
·ç±»
*
* @author gblfy
* @date 2022-03-15
*/
@Component
public class RedisUtils {
@Autowired
private StringRedisTemplate stringRedisTemplate;
// å¦ækeyåå¨çè¯è¿åfasle ä¸åå¨çè¯è¿åtrue
public Boolean setNx(String key, String value, Long timeout) {
Boolean setIfAbsent = stringRedisTemplate.opsForValue().setIfAbsent(key, value);
if (timeout != null) {
stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);
}
return setIfAbsent;
}
/**
* åæ¾stringç±»å
*
* @param key key
* @param data æ°æ®
* @param timeout è¶
æ¶é´
*/
public void setString(String key, String data, Long timeout) {
stringRedisTemplate.opsForValue().set(key, data);
if (timeout != null) {
stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);
}
}
/**
* åæ¾stringç±»å
*
* @param key key
* @param data æ°æ®
*/
public void setString(String key, String data) {
setString(key, data, null);
}
/**
* æ ¹æ®keyæ¥è¯¢stringç±»å
*
* @param key
* @return
*/
public String getString(String key) {
String value = stringRedisTemplate.opsForValue().get(key);
return value;
}
public <T> T getEntity(String key, Class<T> t) {
String json = getString(key);
return JSONObject.parseObject(json, t);
}
public void putEntity(String key, Object object) {
String json = JSONObject.toJSONString(object);
setString(key, json);
}
/**
* æ ¹æ®å¯¹åºçkeyå é¤key
*
* @param key
*/
public boolean delKey(String key) {
return stringRedisTemplate.delete(key);
}
public void setList(String key, List<String> listToken) {
stringRedisTemplate.opsForList().leftPushAll(key, listToken);
}
public StringRedisTemplate getStringRedisTemplate() {
return stringRedisTemplate;
}
}
2.2. å®ä½ç±»
package com.gblfy.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("gblfy_user")
public class UserEntity {
// 主é®
@TableId(value = "user_id", type = IdType.ASSIGN_ID)
private Integer userId;
//ç¨æ·å称
@TableField("name")
private String name;
}
2.3. æ¥å£
package com.gblfy.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.gblfy.entity.UserEntity;
import org.apache.ibatis.annotations.Select;
public interface UserMapper extends BaseMapper<UserEntity> {
}
2.4. æ°æ®åºèæ¬
drop database IF EXISTS `design_pattern`;
create database `design_pattern`;
use `design_pattern`;
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for gblfy_strategy
-- ----------------------------
DROP TABLE IF EXISTS `gblfy_user`;
CREATE TABLE `gblfy_user` (
`user_id` int NOT NULL AUTO_INCREMENT COMMENT 'ç¨æ·ID',
`name` varchar(32) NOT NULL COMMENT 'ç¨æ·å称',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='ç¨æ·è¡¨';
INSERT INTO `gblfy_user` VALUES (1, 'é¨æ');
2.5. æµè¯æ¡ä¾
package com.gblfy.controller;
import com.gblfy.entity.UserEntity;
import com.gblfy.mapper.UserMapper;
import com.gblfy.utils.JvmMapCacheUtils;
import com.gblfy.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 使ç¨è£
饰模å¼~æ¥è¯¢ç¨æ·æ°æ®
*
* @Author gblfy
* @Date 2022-03-15 21:12
**/
@Slf4j
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@Autowired
private RedisUtils redisUtils;
@GetMapping("/getUser")
public UserEntity getUser(Integer userId) {
//ä¸çº§ç¼ååäºçº§ç¼å
//æ¹æ³å+åæ°ç±»å+åæ°
String key = "getUser(Integer)" + userId;
//å
æ¥è¯¢äºçº§ç¼å
UserEntity redisUser = redisUtils.getEntity(key, UserEntity.class);
if (redisUser != null) {
return redisUser;
}
//å
æ¥è¯¢æ们çä¸çº§ç¼åï¼jvmå
ç½®ç¼åï¼
UserEntity jvmUser = JvmMapCacheUtils.getCache(key, UserEntity.class);
if (jvmUser != null) {
//å½ä¸çº§ç¼åä¸ä¸ºç©ºæ¶ï¼å°å
容添å å°äºçº§ç¼årediaä¸ï¼åå°ä¸çº§ç¼åçæ¥è¯¢åå
redisUtils.putEntity(key, jvmUser);
return jvmUser;
}
//æ¥è¯¢æ们çdb
UserEntity dbUser = userMapper.selectById(userId);
if (dbUser == null) {
return null;
}
//å°dbæ¥è¯¢çå
容添å å°ä¸çº§ç¼åä¸ï¼åå°æ°æ®åºåå
JvmMapCacheUtils.putCache(key, dbUser);
return dbUser;
}
}
2.6. æµè¯ææå享
å½ç¬¬ä¸æ¬¡æ¥è¯¢ç¨æ·æ°æ®æ¶æµç¨å¦ä¸ï¼
å å¤æredisä¸æ¯å¦åå¨ï¼å¦æä¸åå¨ï¼æ¥è¯¢jvmç¼åä¸æ¯å¦åå¨
å½ jvmç¼åä¸ä¸åå¨æ¶ï¼æ¥è¯¢æ°æ®åºï¼åå°æ¥è¯¢åºæ¥çæ°æ®æ·»å å°jvmç¼åä¸
å½ç¬¬äºæ¬¡æ¥è¯¢ç¨æ·æ°æ®æ¶æµç¨å¦ä¸ï¼
å å¤æredisä¸æ¯å¦åå¨ï¼å¦æä¸åå¨ï¼æ¥è¯¢jvmç¼åä¸æ¯å¦åå¨
å½ jvmç¼åä¸åå¨æ¶ï¼å å°æ¥è¯¢åºæ¥çæ°æ®æ·»å å°redisç¼åä¸ï¼åè¿åååºç¼åæ°æ®
å½ç¬¬ä¸æ¬¡æ¥è¯¢ç¨æ·æ°æ®æ¶æµç¨å¦ä¸ï¼
å å¤æredisä¸æ¯å¦åå¨ï¼å¦æåå¨ï¼ç´æ¥è¿åç¼åæ°æ®
ä¸ã设计å¤çº§ç¼åæ¡æ¶
3.1. ç¼å容å¨æ½è±¡
package com.gblfy.decoration;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* ç¼å容å¨æ½è±¡
*
* @Author gblfy
* @Date 2022-03-15 21:42
**/
public interface ComponentCache {
/**
* æ ¹æ®keyæ¥è¯¢ç¼åæ°æ®
*
* @param key ç¼åçkey
* @param t ä¼ å
¥å¯¹è±¡åæ°ç±»å
* @param joinPoint ç®æ æ¹æ³å
容
* @param <T> è¿åç对象类å
* @return
*/
<T> T getCacheEntity(String key, Class<T> t, ProceedingJoinPoint joinPoint);
}
3.2. ä¸çº§jvmç¼å
package com.gblfy.decoration.impl;
import com.gblfy.decoration.ComponentCache;
import com.gblfy.utils.JvmMapCacheUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;
/**
* ä¸çº§ç¼åæ¥è¯¢å¤çç±»
*
* @Author gblfy
* @Date 2022-03-15 21:45
**/
@Component
public class JvmComponentCache implements ComponentCache {
// @Autowired
// private UserMapper userMapper;
@Override
public <T> T getCacheEntity(String key, Class<T> t, ProceedingJoinPoint joinPoint) {
//å
æ¥è¯¢æ们çä¸çº§ç¼åï¼jvmå
ç½®ç¼åï¼
T jvmUser = JvmMapCacheUtils.getCache(key, t);
if (jvmUser != null) {
return (T) jvmUser;
}
//æ¥è¯¢æ们çdb
// UserEntity dbUser = userMapper.selectById("1");
// if (dbUser == null) {
// return null;
// }
try {
/**
* å½ä¸çº§ç¼åä¸åå¨æ¶ï¼æ¥è¯¢æ们çdbï¼ç¸å½äºuserMapper.selectById(userId)è¿ä¸è¡ä»£ç
* 1.éè¿aopç´æ¥è·åç®æ 对象çæ¹æ³
* 解æï¼
* ç®çï¼æ§è¡joinPoint.proceed();è¿ä¸è¡å°±ç¸å½äºæ§è¡ç®æ æ¹æ³ï¼ä¸ºäºåææ½è±¡éç¨çï¼
* æ¹æ¡ï¼éç¨aopæ¥å®ç°ä»
æ¤èå·²
*/
Object resultDb = joinPoint.proceed();
//å°dbæ¥è¯¢çå
容添å å°ä¸çº§ç¼åä¸ï¼åå°æ°æ®åºåå
JvmMapCacheUtils.putCache(key, resultDb);
return (T) resultDb;
} catch (Throwable e) {
e.printStackTrace();
return null;
}
}
}
3.3. äºçº§ç¼åæ½è±¡æ¥å£
package com.gblfy.decoration;
/**
* äºçº§ç¼åæ½è±¡æ¥å£
*
* @author gblfy
* @date 2022-03-16
*/
public interface AbstractDecorate extends ComponentCache {
}
3.4. æ°å¢äºçº§ç¼å
package com.gblfy.decoration.impl;
import com.gblfy.decoration.AbstractDecorate;
import com.gblfy.utils.RedisUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* äºçº§ç¼åæ¥è¯¢å¤çç±»
*
* @Author gblfy
* @Date 2022-03-15 21:50
**/
@Component
public class RedistDecorate extends JvmComponentCache implements AbstractDecorate {
@Autowired
private RedisUtils redisUtils;
// @Autowired
// private JvmComponentCache jvmComponentCache;
@Override
public <T> T getCacheEntity(String key, Class<T> t, ProceedingJoinPoint joinPoint) {
//å
æ¥è¯¢äºçº§ç¼å
T tRedis = redisUtils.getEntity(key, t);
if (tRedis != null) {
return (T) tRedis;
}
//å
æ¥è¯¢æ们çä¸çº§ç¼åï¼jvmå
ç½®ç¼åï¼
T tJvm = super.getCacheEntity(key, t, joinPoint);
//å¦æ extends JvmComponentCacheçè¯å¯ä»¥åæä¸é¢super.getCacheEntity(key)è¿ç§ï¼åææ¯è£
饰类ä¸è½new
// UserEntity jvmUser = jvmComponentCache.getCacheEntity(key);
if (tJvm == null) {
return null;
}
//å½ä¸çº§ç¼åä¸ä¸ºç©ºæ¶ï¼å°å
容添å å°äºçº§ç¼årediaä¸ï¼åå°ä¸çº§ç¼åçæ¥è¯¢åå
redisUtils.putEntity(key, tJvm);
return (T) tJvm;
}
}
3.5. Aopä¸èªå®ä¹æ³¨è§£
package com.gblfy.annotation;
import java.lang.annotation.*;
/**
* äºçº§ç¼åæ¥è¯¢aopæ¦æª
*
* @author gblfy
* @date 2022-03-15
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExtGblfyCache {
}
3.6. å®ç°äºçº§ç¼åæ¥è¯¢aopæ¦æª
package com.gblfy.aop;
import com.gblfy.decoration.GblfyCache;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* å®ç°äºçº§ç¼åæ¥è¯¢aopæ¦æª
* èªå®ä¹ExtGblfyCache注解
*
* @author gblfy
* @date 2022-03-15
*/
@Aspect
@Component
@Slf4j
public class ExtAsyncAop {
@Autowired
private GblfyCache gblfyCache;
@Around(value = "@annotation(com.gblfy.annotation.ExtGblfyCache)")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
//è·åç®æ æ¹æ³
Method targetMethod = methodSignature.getMethod();
//ç¼åkeyæ¼æ¥(æ¹æ³å+åæ°ç±»å+åæ°å¼)
String cacheKey = targetMethod.getName() + "," + Arrays.toString(targetMethod.getParameterTypes());
log.info(">>cacheKey:" + cacheKey);
// å¼å§å
æ¥è¯¢äºçº§ç¼åæ¯å¦åå¨
return gblfyCache.getCacheEntity(cacheKey, targetMethod.getReturnType(), joinPoint);
// è¿éçæ³åTçäºæ¹æ³çè¿åç»æç±»åç®è¨ä¹targetMethod.getReturnType()
}
}
3.7. äºçº§ç¼åå¤å£³å°è£
package com.gblfy.decoration;
import com.gblfy.decoration.impl.RedistDecorate;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* äºçº§ç¼åå¤å£³å°è£
*
* @Author gblfy
* @Date 2022-03-15 22:01
**/
@Component
public class GblfyCache {
@Autowired
private RedistDecorate redistDecorate;
public <T> T getCacheEntity(String key, Class<T> t, ProceedingJoinPoint joinPoint) {
return redistDecorate.getCacheEntity(key, t, joinPoint);
}
}
3.8. ç¼å容å¨æ½è±¡
package com.gblfy.controller;
import com.gblfy.annotation.ExtGblfyCache;
import com.gblfy.entity.UserEntity;
import com.gblfy.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 使ç¨è£
饰模å¼~æ¥è¯¢ç¨æ·æ°æ®
*
* @Author gblfy
* @Date 2022-03-15 21:12
**/
@Slf4j
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@GetMapping("/getUser")
@ExtGblfyCache
public UserEntity getUser(Integer userId) {
return userMapper.selectById(userId);
}
}
3.9. 请æ±æµç¨é¾è·¯
å½æ们访é®â
âhttp://localhost:8080/getUser?userId=1â
âæ¹æ³æ¶ï¼ç±äºå¨è¯¥æ¹æ³ä¸æ@ExtGblfyCache注解修饰ï¼å æ¤ï¼ä¼è¢«aopæ¦æªã
3.10. å¼æºé¡¹ç®