基本要求:利用aop实现一个简单的缓存存储、清除的工具,从实际使用上来说,切面应该在provider层。在service层方法调用和数据库查询之间生效。为了简化过程,不要求与数据库交互,数据可以随机生成,不要求使用redis等中间件,可以直接缓存到内存中。
代码实现非常的基础,能够很好的理解AOP以及缓存的基本原理,想要深入理解可以去查阅更多的资料。仅供自己学习。
1、实体类:
public class Student {
String id;
String name;
double score;
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", score=" + score + "]";
}
}
2、自定义注解:
import java.lang.annotation.*;
//自定义缓存注解 获取缓存
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface GetCacheable {
}
//自定义缓存注解 更新缓存注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface UpdateCacheEvict {
}
//自定义缓存注解 清空所有缓存
import java.lang.annotation.*;
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ClearCache {
}
3、AOP缓存切面实现:
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.HashMap;
//aop配合cache注解实现缓存,AOP缓存切面
@Component
@Aspect
public class AopCacheAspect {
private static final Logger logger = LoggerFactory.getLogger(AopCacheAspect.class);
// 为了线程安全,使用Collections.synchronizedMap(new HashMap());
private static Map<String, Object> aopCahche = Collections.synchronizedMap(new HashMap<String, Object>());
@Around(value = "@annotation(com.everhomes.learning.demos.cache.djm.service.GetCacheable)")
public Object getCache(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object result = null;
String key = generateKey(proceedingJoinPoint);
result = aopCahche.get(key);
if (result == null) {
result = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
aopCahche.put(key, result);
}
logger.info("get cache! key={},value={}", key, result);
return result;
}
@Around("@annotation(com.everhomes.learning.demos.cache.djm.service.UpdateCacheEvict)")
public Object evict(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object result = null;
String key = generateKey(proceedingJoinPoint);
result = aopCahche.get(key);
if (result != null) {
aopCahche.remove(key);
}
logger.info("evict cache! key={},result = {}", key, result);
return proceedingJoinPoint.proceed();
}
@Around("@annotation(com.everhomes.learning.demos.cache.djm.service.ClearCache)")
public void clear(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
aopCahche = Collections.synchronizedMap(new HashMap<String, Object>());
}
// 生成缓存 key 可以选择不同生成key值的方式
private String generateKey(ProceedingJoinPoint pJoinPoint) {
StringBuffer cacheKey = new StringBuffer();
String type = pJoinPoint.getArgs().getClass().getSimpleName();
cacheKey.append(StringUtils.join(pJoinPoint.getArgs(), "::"));
cacheKey.append(type);
return cacheKey.toString();
}
}
4、controller层实现:
public interface StudentProvider {
Student getStudentById(String id);
Student updateStudentById(String id);
void clearCache();
}
@RestController
@RequestMapping("/student")
public class StudentController {
@Autowired
private StudentService studentService;
@RequestMapping("/getStudentById")
public Student getStudentById(String id) {
Student student = studentService.getStudentById(id);
return student;
}
@RequestMapping("/updateStudentById")
public Student updateStudentById(String id) {
Student student = studentService.updateStudentById(id);
return student;
}
@RequestMapping("/clearCache")
public void clearCache(String id) {
studentService.clearCache();
}
}
5、Service层实现:
import com.everhomes.learning.demos.cache.djm.controller.Student;
public interface StudentService {
Student getStudentById(String id);
Student updateStudentById(String id);
void clearCache();
}
import com.everhomes.learning.demos.cache.djm.controller.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentProvider studentProvider;
@Override
public Student getStudentById(String id) {
Student student = studentProvider.getStudentById(id);
return student;
}
@Override
public Student updateStudentById(String id) {
Student student = studentProvider.updateStudentById(id);
return student;
}
@Override
public void clearCache() {
studentProvider.clearCache();
}
}
6、Provider层实现:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class StudentProviderImpl implements StudentProvider {
private static final Logger LOGGER = LoggerFactory.getLogger(StudentProviderImpl.class);
@GetCacheable
@Override
public Student getStudentById(String id) {
LOGGER.info("进行查询的" + id + "没有使用缓存,模拟查询数据库");
Student student = new Student();
student.setId("000" + id);
student.setName("我是代号是:000" + id);
student.setScore(80);
return student;
}
@UpdateCacheEvict
@Override
public Student updateStudentById(String id) {
LOGGER.info("对" + id + "进行数据更新!");
Student student = new Student();
student.setId("000" + id);
student.setName("我是代号是:000" + id);
student.setScore(90);
return student;
}
@ClearCache
@Override
public void clearCache() {
LOGGER.info("数据清空了!");
}
}