基於AOP實現快取(本地快取,分散式快取)
阿新 • • 發佈:2021-11-06
1.快取
快取是指提前緩衝、預存資料在非關係型資料庫裡,當進行資料查詢的時候,
先查詢快取再查詢關係型資料庫,可以理解成map<查詢條件,List
對於高併發或者是複雜sql,關係型資料的效率非常低
快取的使用場景:高頻查詢、低頻修改的資料(熱點資料)
快取的工作模型:資料查詢時,先查詢快取,如未命中,查詢關係型資料庫,
將查詢結果存到快取中,返回給客戶端;進行修改時,先更新資料庫,
再刪除快取。
2.本地快取
單機快取
- 基於jvm記憶體,ConcurentHashMap
假如使用aop來實現前置增強,你怎麼實現?
- 使用快取中介軟體,Ehcache
分散式快取
使用redis,適用於tomcat叢集環境
- 編寫spring-cache.xml文件,定義切面
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--配置aop切面增強--> <context:component-scan base-package="com.oracle.shop.cache"></context:component-scan> <aop:config> <!--新增快取--> <aop:aspect ref="cacheAdvice"> <!--更新快取時的一些關鍵字--> <aop:pointcut expression="execution(* com.oracle.shop.service.impl.*.select*(..)) ||execution(* com.oracle.shop.service.impl.*.find*(..)) ||execution(* com.oracle.shop.service.impl.*.get*(..))" id="getCacheCut"/> <aop:around method="getCache" pointcut-ref="getCacheCut"></aop:around> <!--刪除快取--> </aop:aspect> <aop:aspect ref="cacheAdvice"> <!--刪除時的一些關鍵字--> <aop:pointcut id="delCaches" expression="execution(* com.oracle.shop.service.impl.*.delete*(..))|| execution(* com.oracle.shop.service.impl.*.insert*(..))|| execution(* com.oracle.shop.service.impl.*.update*(..))"/> <aop:around method="delCache" pointcut-ref="delCaches"></aop:around> </aop:aspect> </aop:config> </beans>
- 編寫快取的相關介面,編寫實現類,定義相關功能 新增快取,刪除快取,查詢快取
@Service public class CaheServiceImpl implements CacheService { //用來儲存快取的資料 private ConcurrentHashMap<String,Object> concurrentHashMap=new ConcurrentHashMap(); @Override public void addCache(String key, Object value) { System.out.println("新增快取:key"+key+"value:"+value.toString()); concurrentHashMap.put(key,value); } @Override public void removeCache(String key) { ConcurrentHashMap.KeySetView<String, Object> strings = concurrentHashMap.keySet(); for (String s:strings){ if (s.contains(key)){ System.out.println("正在刪除快取"+s); concurrentHashMap.remove(s); } } } @Override public Object getCache(String key) { return concurrentHashMap.get(key); } }
- 編寫通知類,實現業務功能
@Component
public class CacheAdvice implements BeforeAdvice {
@Autowired
private CaheServiceImpl cacheService;
//在方法執行前判斷 時候有快取檔案
public Object getCache(ProceedingJoinPoint jp) throws Throwable{
//獲取UserService
Object target = jp.getTarget();
//方法的引數
Object[] args = jp.getArgs();
//方法的資訊
MethodSignature ms =(MethodSignature) jp.getSignature();
//方法名
String name = ms.getMethod().getName();
//UserService.class
Class c = target.getClass();
//返回值型別
Class returnClass=c.getMethod(name,args[0].getClass()).getReturnType();
//拼接key值
String key = c.getName()+":"+returnClass.getName()+":"+args[0].toString();
Object obj = null;
if ((obj=cacheService.getCache(key))!=null){
return obj;
}else {
//沒有快取,繼續執行查詢
Object result = jp.proceed();
//新增快取
cacheService.addCache(key,result);
return result;
}
}
//資料改變後,刪除快取
public Object delCache(ProceedingJoinPoint jp) throws Throwable{
//獲取所執行的方法資訊
Object target = jp.getTarget();
//UserService.class
Class c = target.getClass();
//拼接key值 類名
String key = c.getName();
cacheService.removeCache(key);
return jp.proceed();
}
}
3.分散式快取(註解方式)
分散式快取解決方案
主流使用redis來解決
spring-cache 框架 可以整合各種快取容器
開發步驟:
1:引入spring-context(spring-cache)
2:redis相關的,redis.properties 配置spring-redis.xml
3:spring-cache的配置檔案
spring-redis-cache.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd">
<!-- 開啟快取的註解支援,意味著將來掃包器會掃到cache相關注解 -->
<cache:annotation-driven/>
<!--快取管理器,可配可不配-->
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="com.oracle.shop.cache.RedisCache">
<property name="name" value="redisCache"></property>
</bean>
</set>
</property>
</bean>
</beans>
4:自定義快取實現類(實現spring-cache下面的cache介面)
5:使用註解來定義快取策略(通常情況下快取定義在service級別)
注意事項:將來被快取的資料model,必須得實現序列化介面
在service的類上加上
@CacheConfig(cacheManager = "cacheManager",cacheNames = "redisCache")
給該service指定使用哪個快取管理器中的哪個快取
@cacheable (查詢快取)
service中新增add、insert開頭的方法
@cacheput (新增快取)
service中 更新、刪除的操作delete使用該註解
@cacheEvict(beforeInvocation = false,allEntries = true )
(刪除快取)
@CacheConfig(cacheManager = "cacheManager",cacheNames = "redisCache")
@Service
public class UserServiceImpl implements UserService{
@Cacheable(key = "#user")
@Override
public User findUserByUsernameAndPassword(User user) {
return userMapper.findUserByUsernameAndPassword(user);
}
}