1. 程式人生 > >利用AOP實現一個簡單的快取儲存、清除的工具

利用AOP實現一個簡單的快取儲存、清除的工具

基本要求:利用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("資料清空了!");
	}
}

 

每天努力一點,每天都在進步。