应用场景##
- 数据访问采用ORM方式(Hibernate) 直接访问数据库,在访问量小、并发性小、数据量小时,可正常访问,反之则服务响应能力低。
- 福利彩蛋
目标&要解决的问题##
- 自定义注解&Spring AOP为项目加入Redis缓存依赖提高应用程序的响应能力(可重用)
项目扩充承接于http://www.jianshu.com/p/25039d901ac2
难点##
设置缓存的失效策略,缓存数据的Struct选取,切面(Aspect)的编写
方法&扩充步骤##
1.扩充build.gradle 脚本文件
//https://mvnrepository.com/artifact/org.springframework.data/spring-data-redis 项目添加redis支持 compile group: 'org.springframework.data', name: 'spring-data-redis', version: '1.4.1.RELEASE' // https://mvnrepository.com/artifact/redis.clients/jedis redis 基于java的Redis客户端调用实现 compile group: 'redis.clients', name: 'jedis', version: '2.6.1' // https://mvnrepository.com/artifact/com.alibaba/fastjson // 采用阿里巴巴fastjson 进行对象&json字符串的序列化与反序列化 compile group: 'com.alibaba', name: 'fastjson', version: '1.2.21'
2.扩充Spring 配置文件,添加Redis相关Java Bean 到Ioc容器中
为了符合开闭原则,重新创建Spring 配置文件 spring-redis.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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" 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"> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxIdle" value="100" /> <!-- <property name="max" value="${redis.maxActive}" /> <property name="maxWait" value="${redis.maxWait}" />--> <property name="testOnBorrow" value="true" /> </bean> <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="127.0.0.1" p:port="6379" p:password="ls" p:pool-config-ref="jedisPoolConfig"/> <bean id="redisTemplateForString" class="org.springframework.data.redis.core.StringRedisTemplate"> <property name="connectionFactory" ref="connectionFactory" /> </bean></beans>
3.自定义两个注解
- RedisCahe: 标识缓存 注解
- RedisEvit: 标识缓存清除 注解
代码如下:
RedisCahe.java
package com.fxmms.common.rediscache.redisannotation;import java.lang.annotation.*;/** * Created by mark on 2023年04月13日/29. * @usage 缓存注解类 */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)@Documentedpublic @interface RedisCache { Class type();//被代理类的全类名,在之后会做为redis hash 的key}
RedisEvit.java
package com.fxmms.common.rediscache.redisannotation;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * Created by mark on 2023年04月13日/29. * @usage 清除过期缓存注解,放置于update delete insert 类型逻辑之上 */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface RedisEvict { Class type();}
4.RedisCacheAspect.java 切面程序
package com.fxmms.common.rediscache.redisaspect;import com.fxmms.common.rediscache.redisannotation.RedisCache;import com.fxmms.common.rediscache.redisannotation.RedisEvict;import com.fxmms.common.util.FastJsonUtil;import com.fxmms.common.util.JsonUtil;import org.apache.log4j.Logger;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.aspectj.lang.reflect.MethodSignature;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.stereotype.Component;import java.lang.reflect.Method;import java.util.List;/** * Created by mark on 2023年04月13日/29. */@Aspect@Component@SuppressWarnings(value = {"rawtypes", "unchecked"})public class RedisCacheAspect { private static final Logger logger = Logger.getLogger(RedisCacheAspect.class); /** * 分隔符 生成key 格式为 类全类名|方法名|参数所属类全类名 **/ private static final String DELIMITER = "|"; /** * spring-redis.xml配置连接池、连接工厂、Redis模板 **/ @Autowired @Qualifier("redisTemplateForString") StringRedisTemplate srt; /** * Service层切点 使用到了我们定义的 RedisCache 作为切点表达式。 * 而且我们可以看出此表达式基于 annotation。 * 并且用于内建属性为查询的方法之上 */ @Pointcut("@annotation(com.fxmms.common.rediscache.redisannotation.RedisCache)") public void redisCacheAspect() { } /** * Service层切点 使用到了我们定义的 RedisEvict 作为切点表达式。 * 而且我们可以看出此表达式是基于 annotation 的。 * 并且用于内建属性为非查询的方法之上,用于更新表 */ @Pointcut("@annotation(com.fxmms.common.rediscache.redisannotation.RedisEvict)") public void redisCacheEvict() { } @Around("redisCacheAspect()") public Object cache(ProceedingJoinPoint joinPoint) { // 得到类名、方法名和参数 String clazzName = joinPoint.getTarget().getClass().getName(); String methodName = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); // 根据类名、方法名和参数生成Key logger.info("key参数: