如何在项目中使用 aop 技术? [学习核心包系列一]
项目的核心代码都封装在核心包中. 本系列文章记录笔者阅读源码的过程和相应的实践.
1. 问题: 项目的本地缓存该如何设计?
项目的本地缓存使用了 aop + 自定义注解 方式实现.
原理如下:
- 通过一个注解 加上aop 把所有的自定义注解 全部拦截到一个方法里头
- 在这个方法里面 先进行查询 可以去redis 项目采用的caffeine
- 如果查到了 就直接返回数据 不执行数据库sql
- 如果查不到 就继续执行sql
- caffeine 相当于是一个高级map
2. 如何实现上述设计?
1 2 3
| 需求:
定义一个方法根据小写字母生成大写字母. 定义一个 Map 保存已生成的数据, 如果 Map 已存在则直接打印, 不存在则调用方法获取.
|
2.1.1 在 pom.xml 中引入依赖, 生成一个项目
1 2 3 4 5 6 7 8
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
|
${springboot.version}
表示一个常量属性一般定义在 pom.xml. 多个依赖使用同一版本号避免冲突.
2.1.2 定义一个controller接口
1 2 3 4
| @RequestMapping(value = "/getUpperCase/{str}") public String getUpperCase(@PathVariable("str") String str) { return userService.getUpperCase(str); }
|
2.1.3 定义一个serive方法
1 2 3 4 5 6
| public String getUpperCase(String str) { System.out.println("进入方法了"); return str.toUpperCase(Locale.ROOT); }
|
2.1.4 测试
2.1.5 增加自定义注解
1 2
| public @interface CacheZJ { }
|
2.1.6 增加缓存处理接口
1 2 3 4 5 6 7 8 9 10 11 12
| public interface YxCacheHandle { Object get(String var1);
void put(String var1, Object var2);
boolean delete(String var1);
String getCacheName();
Map<Object, Object> getCacheAll(); }
|
2.1.7 增加缓存接口实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @Component public class MapHandleImpl implements YxCacheHandle { Map<String,Object> cacheMap = new HashMap<>();
@Override public Object get(String var1) { String result = (String)cacheMap.get(var1); System.out.println("缓存取的数据:" + result); return result; }
@Override public void put(String var1, Object var2) { cacheMap.put(var1, var2); }
@Override public boolean delete(String var1) { cacheMap.remove(var1); return true; }
@Override public String getCacheName() { return null; }
@Override public Map<Object, Object> getCacheAll() { return null; } }
|
2.1.8 增加注解拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Aspect @Component public class CacheZJAspect { @Resource YxCacheHandle yxCacheHandle;
@Pointcut("@annotation(com.annotation.CacheZJ)") public void cacheOpr() { }
@Around("cacheOpr()") public Object doAround(ProceedingJoinPoint pjp) throws Throwable { String args = (String)pjp.getArgs()[0]; String result ; if (yxCacheHandle.get(args) == null) { result = (String) pjp.proceed(); yxCacheHandle.put(args,result); } return yxCacheHandle.get(args); }
}
|
2.1.9 把注解加到 serive 方法上, 并测试
1 2 3 4 5
| @CacheZJ public String getUpperCase(String str) { System.out.println("进入方法了"); return str.toUpperCase(Locale.ROOT); }
|