2017-10-19 79 views
0

我刚刚了解到Redis和Redisson。基本上我试图使用Redis来存储AcessTokens/RefreshTokens用于授权在我的应用程序。 所以我想存储具有到期时间的令牌。我使用Spring Data Redis来存储令牌,但没有Api会使Map中的每个条目过期。我遇到了这个帖子Spring Data Redis Expire Key,因此抬头看着Redisson。我尝试了一个简单的Maven Java项目来测试过期。 这里的pom.xml:已过期Redisson Keys仍在Redis Cli中可见

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 

    <groupId>com.bridgelabz</groupId> 
    <artifactId>redissonApp</artifactId> 
    <version>0.0.1-SNAPSHOT</version> 
    <packaging>jar</packaging> 

    <name>redissonApp</name> 
    <url>http://maven.apache.org</url> 

    <properties> 
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
    </properties> 

    <dependencies> 
     <dependency> 
      <groupId>junit</groupId> 
      <artifactId>junit</artifactId> 
      <version>3.8.1</version> 
      <scope>test</scope> 
     </dependency> 

     <dependency> 
      <groupId>org.redisson</groupId> 
      <artifactId>redisson</artifactId> 
      <version>3.3.0</version> 
     </dependency> 

    </dependencies> 
</project> 

下面是Token类

package com.bridgelabz.redissonApp; 

public class Token { 

    private String accessToken; 
    private int id; 

    public Token() { } 


    public Token(String accessToken, int id) { 

     this.accessToken = accessToken; 
     this.id = id; 
    } 

    public String getAccessToken() { 
     return accessToken; 
    } 

    public void setAccessToken(String accessToken) { 
     this.accessToken = accessToken; 
    } 

    public int getId() { 
     return id; 
    } 

    public void setId(int id) { 
     this.id = id; 
    } 

    @Override 
    public String toString() { 
     return "Token [accessToken=" + accessToken + ", id=" + id + "]"; 
    } 

} 

这里是我的演示应用程序:

package com.bridgelabz.redissonApp; 

import java.util.concurrent.TimeUnit; 

import org.redisson.Redisson; 
import org.redisson.api.LocalCachedMapOptions; 
import org.redisson.api.RMapCache; 
import org.redisson.api.RedissonClient; 
import org.redisson.api.LocalCachedMapOptions.EvictionPolicy; 
import org.redisson.config.Config; 


public class App { 
    public static void main(String[] args) { 
     Config config = new Config(); 

     config.useSingleServer().setAddress("127.0.0.1:6379"); 

     // LocalCachedMapOptions localCachedMapOptions = 
     // LocalCachedMapOptions.defaults() 
     // .evictionPolicy(EvictionPolicy.LFU); 

     RedissonClient redisson = Redisson.create(config); 

     try { 

      RMapCache<Integer, Token> map = redisson.getMapCache("TestMap"); 

      Token myToken = new Token("abc", 1); 

      map.put(1, myToken, 10, TimeUnit.SECONDS); 

      System.out.println("Stored value with key 1 is: " + map.get(1)); 

     } 

     finally { 

      redisson.shutdown(); 

     } 

    } 
} 

运行App.java后,我得到的输出我得到输出为:

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". 
SLF4J: Defaulting to no-operation (NOP) logger implementation 
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. 
Stored value with key 1 is: Token [accessToken=abc, id=1] 

和公正的评论看跌期权代码,10秒钟后运行的应用程序给我的部分期望的结果:

LF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". 
SLF4J: Defaulting to no-operation (NOP) logger implementation 
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. 
Stored value with key 1 is: null 

但是当我运行Redis的-CLI我仍然在输出所获得的价值:

127.0.0.1:6379> hget TestMap 1 
"\x00\x00\x00\x00\x00\x00\x00\x00H\x00\x00\x00\x00\x00\x00\x00{\"@class\":\"com.bridgelabz.redissonApp.Token\",\"accessToken\":\"abc\",\"id\":1}" 

为什么不从redis中删除密钥?仅供参考:我的本地机器上的所有测试只包括redis。

回答

1

Redis不支持单个元素驱逐开箱即用。因此Redisson建立了自己的解决方案并将其命名为MapCache

因此,与MapCache一样,您现在有两个级别的过期控制:Redis提供的关键级别和Redisson提供的现场级别。

在您的测试代码:

RMapCache<Integer, Token> map = redisson.getMapCache("TestMap"); 

Token myToken = new Token("abc", 1); 

map.put(1, myToken, 10, TimeUnit.SECONDS); 

您已设置在该领域的哈希TestMap1到期。这意味着哈希没有对它设置的期限,而是对其中一个字段设置了到期日。因此,当您使用redis-cli来查找时,散列仍然存在。当Redisson到期过程开始时,它最终会消失。

0

我不知道推理,但是当我在Spring Web App中使用相同的代码但未在简单的Java应用程序中工作时,密钥已过期。 这里是TokenDaoImpl.java代码:

import java.io.IOException; 
import java.util.UUID; 
import java.util.concurrent.TimeUnit; 

import javax.annotation.PostConstruct; 
import javax.annotation.PreDestroy; 

import org.apache.log4j.Logger; 
import org.redisson.Redisson; 
import org.redisson.api.RMapCache; 
import org.redisson.api.RedissonClient; 
import org.redisson.config.Config; 
import org.springframework.stereotype.Repository; 

import com.bridgelabz.restApiDemo.entity.Token; 

@Repository 
public class TokenDaoImpl implements TokenDao { 

    Logger logger = Logger.getLogger(TokenDaoImpl.class); 

    RedissonClient redissonClient; 

    RMapCache<String, Token> tokenMap; 

    @PostConstruct 
    public void initRedisson() { 

     Config config = null; 
     try { 
      config = Config.fromJSON("{\n" + " \"singleServerConfig\":{\n" 
        + "  \"idleConnectionTimeout\":10000,\n" + "  \"pingTimeout\":1000,\n" 
        + "  \"connectTimeout\":10000,\n" + "  \"timeout\":3000,\n" + "  \"retryAttempts\":3,\n" 
        + "  \"retryInterval\":1500,\n" + "  \"reconnectionTimeout\":3000,\n" 
        + "  \"failedAttempts\":3,\n" + "  \"password\":null,\n" 
        + "  \"subscriptionsPerConnection\":5,\n" + "  \"clientName\":null,\n" 
        + "  \"address\": \"redis://127.0.0.1:6379\",\n" 
        + "  \"subscriptionConnectionMinimumIdleSize\":1,\n" 
        + "  \"subscriptionConnectionPoolSize\":50,\n" + "  \"connectionMinimumIdleSize\":10,\n" 
        + "  \"connectionPoolSize\":64,\n" + "  \"database\":0,\n" 
        + "  \"dnsMonitoring\":false,\n" + "  \"dnsMonitoringInterval\":5000\n" + " },\n" 
        + " \"threads\":0,\n" + " \"nettyThreads\":0,\n" + " \"codec\":null,\n" 
        + " \"useLinuxNativeEpoll\":false\n" + "}"); 
     } catch (IOException e1) { 
      logger.info("******Inside Config Catch"); 
      e1.printStackTrace(); 
     } 

     logger.info("**************Config Object" + config); 

     redissonClient = Redisson.create(config); 

     tokenMap = redissonClient.getMapCache("tokenMap"); 
    } 

    @PreDestroy 
    public void redissonShutdown() { 
     redissonClient.shutdown(); 
    } 

    public TokenDaoImpl() { 

    } 

    @Override 
    public Token generateToken(String tokenType, int uid) { 

     // first generate the token 
     String tokenValue = UUID.randomUUID().toString().replaceAll("-", ""); 
     logger.info("******Generated access token is " + tokenValue); 

     Token token = new Token(tokenType, tokenValue, uid); 

     // save the token in redis cache with expiration depending upon tokenType 
     switch (tokenType) { 
     case "accessToken": 
      tokenMap.put(tokenValue, token, 15, TimeUnit.MINUTES); 
      break; 

     case "refreshToken": 
      tokenMap.put(tokenValue, token, 30, TimeUnit.MINUTES); 
      break; 

     case "forgotToken": 
      tokenMap.put(tokenValue, token, 30, TimeUnit.MINUTES); 
      break; 

     default: 
      logger.info("**********Please specify correct token type!"); 
      break; 
     } 

     return token; 
    } 

    @Override 
    public boolean verifyToken(String tokenValue) { 

     Token token = tokenMap.get(tokenValue); 

     logger.info("******Token from redis for verification" + token); 

     if (token != null) { 
      return true; 
     } 

     return false; 
    } 

} 

此前,运行Java应用程序的时候,我在其中具有MapName_session_timeout redis-其中一个我创建即TokenMap和新映射表地图,甚至之后的键将保持指定的到期日。现在所有的键都被正确删除。