1. 程式人生 > 其它 >基於AOP實現快取(本地快取,分散式快取)

基於AOP實現快取(本地快取,分散式快取)

1.快取

​ 快取是指提前緩衝、預存資料在非關係型資料庫裡,當進行資料查詢的時候,
​ 先查詢快取再查詢關係型資料庫,可以理解成map<查詢條件,List>
​ 對於高併發或者是複雜sql,關係型資料的效率非常低
​ 快取的使用場景:高頻查詢、低頻修改的資料(熱點資料)
​ 快取的工作模型:資料查詢時,先查詢快取,如未命中,查詢關係型資料庫,
​ 將查詢結果存到快取中,返回給客戶端;進行修改時,先更新資料庫,
​ 再刪除快取。

2.本地快取

單機快取

  • 基於jvm記憶體,ConcurentHashMap

假如使用aop來實現前置增強,你怎麼實現?

  • 使用快取中介軟體,Ehcache
    分散式快取
    使用redis,適用於tomcat叢集環境
  1. 編寫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>
  1. 編寫快取的相關介面,編寫實現類,定義相關功能 新增快取,刪除快取,查詢快取
@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);
    }
}
  1. 編寫通知類,實現業務功能
@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);
    }
}