基于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);
    }
}
posted @ 2021-11-06 12:56  2333gyh  阅读(299)  评论(0编辑  收藏  举报