基于AOP实现缓存(本地缓存,分布式缓存)
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);
}
}