1. 程式人生 > >Spring Boot中使用快取Redis、EhCache

Spring Boot中使用快取Redis、EhCache

快取相信各位同學都或多或少用到過,畢竟不能把所有壓力都給資料庫。今天來簡單總結一下下在Spring Boot中使用Redis和EhCache快取O(∩_∩)O~
Spring Boot本身是支援多種快取實現的,其中提供了4個註解來幫助大家使用快取:

  • @EnableCaching 開啟快取支援
  • @Cacheable 先檢查快取是否存在,若存在,則直接返回快取中結果;若不存在,則執行方法獲取結果,並將結果放到快取中
  • @CacheEvict 清除快取
  • @CachePut 始終執行方法,並將結果放到快取中

先說一下EhCache,EhCache是在記憶體中的快取,也就是說,程式在,快取就在,程式停了,快取就沒了,要使用EhCache,首先引入pom starter:

	<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-cache</artifactId>
	</dependency>

在啟動類上開啟快取支援:

@SpringBootApplication
@EnableCaching
public class Application {
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

下來只需要在方法上加上註解就行了:

@Cacheable(value="user",key = "#user.id")
public User findOne(User user) {
      User u=userRepository.findOne(user.getId());
      return u;
}

可以看到,在註解中指定了value和key兩個引數,value是用來歸類用的,以上方法所生成的所有快取在快取庫中都存放在user資料夾下;key是用來指定快取鍵值的,它有兩種生成策略——預設策略和自定義策略,其預設策略如下:

  • 如果方法沒有引數,則使用0作為key
  • 如果只有一個引數,則使用該引數作為key
  • 如果引數多於一個,則使用所有引數的hashCode作為key

很明顯,我這裡自定義了key,指定為引數user物件的id。
key支援通過Sping EL表示式來指定,幾個一看就懂的栗子:

   @Cacheable(value="user", key="#id")
   public User find(Integer id) {
      return null;
   }
   
   @Cacheable(value="user", key="#p0")
   public User find(Integer id) {
      return null;
   }

   @Cacheable(value="user", key="#user.id")
   public User find(User user) {
      return null;
   }

   @Cacheable(value="user", key="#p0.id")
   public User find(User user) {
      return null;
   }

除了上述使用方法引數生成key以外,Spring還提供了一個root物件來生成key:

屬性名稱 描述 示例
methodName 當前方法名 #root.methodName
target 當前被呼叫的物件 #root.target
targetClass 當前被呼叫的物件的class #root.targetClass
args 當前方法引數組成的陣列 #root.args[0]
caches 當前被呼叫的方法使用的Cache #root.caches[0].name

另外,如果EhCache有別的設定,那麼可以新建一個ehcache.xml,在application.properties中配好這個配置檔案即可:

spring.cache.type=ehcache
spring.cache.ehcache.config=static/ehcache.xml

下面說一下Redis,同樣首先引入pom starter:

<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

同樣通過@EnableCaching開啟快取支援。

由於Redis是獨立安裝的,它就像資料庫一樣可以持久化資料,所以必然也像資料庫一樣有連線地址,在application.yml中配置如下:

	spring:
	  redis:
	    database: 0
	    host: 10.155.20.162
	    port: 6379
	    pool:
	      max-active: 80
	      max-wait: -1
	      max-idle: 80
	      min-idle: 0
	    timeout: 5000

吶,EhCache的時候用的properties配置檔案,Redis用的yml配置檔案喲,各取所愛吧~

同樣在方法上面使用@Cacheable、@CacheEvict、@CachePut來操作快取。
這裡介紹一下keyGenerator,前面key的生成策略就是它控制的,Spring允許我們自定義這個Generator,舉個栗子:

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport{
    //自定義key生成方式
    @Bean
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                StringBuilder sb = new StringBuilder();
                String[] value = new String[1];
                Cacheable cacheable = method.getAnnotation(Cacheable.class);
                if (cacheable != null) {
                    value = cacheable.value();
                }
                CachePut cachePut = method.getAnnotation(CachePut.class);
                if (cachePut != null) {
                    value = cachePut.value();
                }
                CacheEvict cacheEvict = method.getAnnotation(CacheEvict.class);
                if (cacheEvict != null) {
                    value = cacheEvict.value();
                }
                sb.append(value[0]);
                sb.append(":");
                sb.append(params[0].toString());
                return sb.toString();
            }
        };
    }

    //快取管理器
    @Bean
    public CacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
        cacheManager.setDefaultExpiration(43200);  //設定快取過期時間
        return cacheManager;
    }
    
    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory){
        StringRedisTemplate template = new StringRedisTemplate(factory);
        @SuppressWarnings({ "rawtypes", "unchecked" })
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

可以看到,這個Config中有3個Bean,第1個Bean中用註解的value屬性+":"+第一個引數作為key值的生成策略;第2個Bean中指定了快取的全域性過期時間;第3個Bean中定義了RedisTemplate。

ok,以上講了通過註解來操作快取,不過有的時候,並不一定存在方法,只是單純地想操作某個key值的快取,咋辦?這個時候就要用到RedisTemplate啦,Spring中自帶這個物件,包括上面也自定義了這個物件,我們在需要使用的地方把它注入進來就可以了。不過,通常我們會先寫個工具類:

@Service
public class RedisService {
    @Autowired
    @Qualifier("stringRedisTemplate")
    RedisTemplate template;

    public void setValue(String key, Object val) {
        template.opsForValue().set(key, val);
    }

    public void setValue(String key, Object val, int time, TimeUnit unit) {
        template.opsForValue().set(key, val, time, unit);
    }

    public Object getValue(String key) {
        return template.opsForValue().get(key);
    }

    public void deleteValue(String key){
        template.delete(key);
    }
}

可以看到,我這邊使用的是stringRedisTemplate,具體還有什麼其它型別,各位同學自己去發現一以下吧~