1. 為何要用緩存、緩存的目的是為了什么?(https://my.oschina.net/u/3378039/blog/2986697)
一個程序的瓶頸在於數據庫,內存的速度遠遠大於硬盤的速度,當我們一次又一次請求數據庫或遠程服務時會導致大量的時間耗費在數據庫操作或遠程方法調用上,以致於 程序性能惡化,使用數據緩存可以解決此問題。
下面是常用的緩存管理器以及可用注解方式實現緩存機制的集中類型
2.@Cacheable/@CachePut/@CacheEvict/@Caching介紹(https://blog.csdn.net/wjacketcn/article/details/50945887)
具體介紹參見鏈接。
其中cacheable的源碼如下:
1 public @interface Cacheable { 2 3 /** 4 * 設定要使用的cache的名字,必須提前定義好緩存 5 */ 6 @AliasFor("cacheNames") 7 String[] value() default {}; 8 9 /** 10 * 同value(),決定要使用那個/些緩存 11 */ 12 @AliasFor("value") 13 String[] cacheNames() default {}; 14 15 /** 16 * 使用SpEL表達式來設定緩存的key,如果不設置默認方法上所有參數都會作為key的一部分 17 */ 18 String key() default ""; 19 20 /** 21 * 用來生成key,與key()不可以共用 22 */ 23 String keyGenerator() default ""; 24 25 /** 26 * 設定要使用的cacheManager,必須先設置好cacheManager的bean,這是使用該bean的名字 27 */ 28 String cacheManager() default ""; 29 30 /** 31 * 使用cacheResolver來設定使用的緩存,用法同cacheManager,但是與cacheManager不可以同時使用 32 */ 33 String cacheResolver() default ""; 34 35 /** 36 * 使用SpEL表達式設定出發緩存的條件,在方法執行前生效 37 */ 38 String condition() default ""; 39 40 /** 41 * 使用SpEL設置出發緩存的條件,這里是方法執行完生效,所以條件中可以有方法執行后的value 42 */ 43 String unless() default ""; 44 45 /** 46 * 用於同步的,在緩存失效(過期不存在等各種原因)的時候,如果多個線程同時訪問被標注的方法 47 * 則只允許一個線程通過去執行方法 48 */ 49 boolean sync() default false; 50 51 }
(下圖來源於https://www.cnblogs.com/psy-code/p/9537830.html)
3.使用guava和caffeine緩存(據說spring5開始已經開始用caffeine替換guava)。
以下圖列舉集中常用的緩存的性能比較柱狀圖,來源於(https://blog.csdn.net/qq_35981283/article/details/82354081#commentBox)
下面主要以guava和caffeine為例,代碼如下:
a.使用guava的情景,代碼如下(參考網址https://blog.csdn.net/chinabestchina/article/details/78009220):
application-guava.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cache="http://www.springframework.org/schema/cache" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> 5 <cache:annotation-driven/> 6 <bean id="cacheManager" class="org.springframework.cache.guava.GuavaCacheManager"> 7 <property name="cacheSpecification" value="concurrencyLevel=4,expireAfterAccess=100s,expireAfterWrite=100s" /> 8 <property name="cacheNames"> 9 <list> 10 <value>guavaCache</value> 11 </list> 12 </property> 13 </bean> 14 </beans>
1 package com.alice.bean; 2 3 public class Student { 4 public Integer id; 5 public String name; 6 7 public Integer getId() { 8 return id; 9 } 10 11 public void setId(Integer id) { 12 this.id = id; 13 } 14 15 public String getName() { 16 return name; 17 } 18 19 public void setName(String name) { 20 this.name = name; 21 } 22 }
1 package com.alice.guava; 2 3 import com.alice.bean.Student; 4 5 public interface StudentService { 6 public Student getStudent(Integer id); 7 8 public Student updateStudent(Student stu); 9 10 public void deleteStudent(Integer id); 11 12 public void deleteAllStudent(); 13 14 public void myDelete(Integer id); 15 }
1 package com.alice.guava; 2 3 import com.alice.bean.Student; 4 import org.springframework.aop.framework.AopContext; 5 import org.springframework.cache.annotation.CacheEvict; 6 import org.springframework.cache.annotation.CachePut; 7 import org.springframework.cache.annotation.Cacheable; 8 import org.springframework.stereotype.Service; 9 10 @Service("studentGuavaCache") 11 public class StudentGuavaCacheImpl implements StudentService { 12 13 @Cacheable(value = "guavaCache",key="'id_'+#id",condition = "#id<3") 14 public Student getStudent(Integer id) { 15 Student stu = new Student(); 16 stu.setId(id); 17 stu.setName("apple"); 18 return stu; 19 } 20 21 @CachePut(value = "guavaCache",key="'id_'+#stu.getId()") 22 public Student updateStudent(Student stu){ 23 System.out.println("update stu"); 24 return stu; 25 } 26 27 28 @CacheEvict(value = "guavaCache",key="'id_'+#id") 29 public void deleteStudent(Integer id){ 30 31 System.out.println("delete student "+id); 32 } 33 34 public void myDelete(Integer id){ 35 try { 36 StudentService ss = (StudentService) AopContext.currentProxy(); 37 ss.deleteStudent(id); 38 return ; 39 }catch (Exception e){ 40 e.printStackTrace(); 41 42 } 43 this.deleteStudent(id); 44 } 45 46 @CacheEvict(value = "guavaCache",allEntries = true) 47 public void deleteAllStudent(){ 48 49 System.out.println("delete all student "); 50 } 51 }
1 package com.alice.guava; 2 3 import com.alice.bean.Student; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5 import org.springframework.util.Assert; 6 7 public class SpringGuavaCacheMain { 8 public static void main(String[] args) { 9 ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("classpath:application-cache.xml","classpath:application-spring.xml","classpath:application-mybatis.xml"); 10 StudentService studentService = (StudentService) ac.getBean("studentGuavaCache"); 11 12 Integer id =1; 13 Student stu = studentService.getStudent(id); //新建緩存 14 stu = studentService.getStudent(id); //從緩存中取 15 16 studentService.myDelete(id); 17 stu = studentService.getStudent(id); //從緩存中取 18 19 stu.setName("banana"); //重新設置值 20 Student stu1 = studentService.getStudent(id); 21 stu.setName("banana"); 22 studentService.updateStudent(stu); //更新緩存 23 stu = studentService.getStudent(id); //從緩存中取出新值 24 25 stu = new Student(); //新實例 26 stu.setId(0); 27 studentService.updateStudent(stu); //用新建的實例進行更新,會新建緩存 28 stu = studentService.getStudent(0); //從緩存中取 29 30 studentService.deleteStudent(id); // 刪除緩存 31 stu = studentService.getStudent(id); //再次新建緩存 32 33 id=2; 34 stu = studentService.getStudent(id); //新建緩存 35 studentService.deleteAllStudent(); //刪除所有緩存 36 id=1; 37 stu = studentService.getStudent(id); //因所有緩存被前一步清除,會新建緩存 38 39 id=5; 40 stu = studentService.getStudent(id); //不會新建緩存 因為設置了緩存條件必須小於3 41 stu = studentService.getStudent(id); //因沒有緩存,不會從緩存中取 42 43 Assert.notNull(stu,"deprecated"); 44 } 45 }
2.使用caffeine
這里擴展了下原本的caffeineManager
1 package com.alice.caffeine; 2 3 import com.github.benmanes.caffeine.cache.Caffeine; 4 import org.springframework.cache.caffeine.CaffeineCacheManager; 5 6 import java.util.concurrent.TimeUnit; 7 8 public class CaffeineCacheExtManager extends CaffeineCacheManager { 9 10 public CaffeineCacheExtManager(){ 11 super(); 12 } 13 /** 14 * Construct a CaffeineCacheExtManager managing caches with expireAfterWrite feature 15 * 16 * @param duration 17 * @param timeUnit 18 */ 19 public CaffeineCacheExtManager(long duration, String timeUnit) { 20 this.setCaffeine(Caffeine.newBuilder().expireAfterWrite(duration, TimeUnit.valueOf(timeUnit.toUpperCase()))); 21 } 22 23 }
application-caffeine.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:cache="http://www.springframework.org/schema/cache" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> 6 <cache:annotation-driven/> 7 8 <bean id="cacheManager" class="org.springframework.cache.caffeine.CaffeineCacheManager"/> 9 10 <bean id="tenSecondCacheManager" class="com.alice.caffeine.CaffeineCacheExtManager"> 11 <constructor-arg name="duration" value="10"/> 12 <constructor-arg name="timeUnit" value="SECONDS"/> 13 </bean> 14 </beans>
1 package com.alice.caffeine; 2 3 import com.alice.bean.Student; 4 5 public interface StudentService { 6 public Student getStudent(Integer id); 7 }
1 package com.alice.caffeine; 2 3 import com.alice.bean.Student; 4 import org.springframework.aop.framework.AopContext; 5 import org.springframework.cache.annotation.CacheEvict; 6 import org.springframework.cache.annotation.CachePut; 7 import org.springframework.cache.annotation.Cacheable; 8 import org.springframework.stereotype.Service; 9 10 @Service("CaffeineCache") 11 public class StudentCaffeineCacheImpl implements StudentService { 12 13 @Cacheable(cacheManager = CacheMgmtName.TEN_SECOND_CACHE_MANAGER,cacheNames =CacheNames.QUERY_STUINFO_CACHE, key="'id_'+#id",condition = "#id<3") 14 public Student getStudent(Integer id) { 15 Student stu = new Student(); 16 stu.setId(id); 17 stu.setName("apple"); 18 return stu; 19 } 20 }
1 package com.alice.caffeine; 2 3 import com.alice.bean.Student; 4 import com.alice.caffeine.StudentService; 5 import org.springframework.context.support.ClassPathXmlApplicationContext; 6 7 public class test { 8 public static void main(String[] args){ 9 ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("classpath:application-cache.xml","classpath:application-spring.xml","classpath:application-mybatis.xml","classpath:application-caffeine.xml"); 10 StudentService studentService = (StudentService) ac.getBean("CaffeineCache"); 11 int id =1; 12 Student stu = studentService.getStudent(id); 13 stu = studentService.getStudent(id); 14 } 15 }