spring boot 中使用redis session
spring boot 默認的httpsession是存在內存中。這種默認方式有幾個缺點:1、當分布式部署時,存在session不一致的問題;2、當服務重啟時session就會丟失,這時候用戶就需要重新登陸,可能導致用戶數據丟失。通常會使用redis來保存session。
在spring boot中利用redis來保存session是非常簡單。只需要簡單的幾步就可以了。可以參考官方教程。https://docs.spring.io/spring-session/docs/current/reference/html5/guides/boot-redis.html
配置流程:
1、pom文件中添加依賴
<dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency>
註意:如果pom文件沒有引入 spring-boot-starter-data-redis,則需要引入,否則無法自動配置redis,出現這個錯誤‘org.springframework.data.redis.connection.RedisConnectionFactory‘ that could not be found.
2、在配置文件中添加相關配置
#配置sesion使用redis spring.session.store-type=redis 設置session的一些屬性 server.servlet.session.cookie.http-only=true server.servlet.session.timeout= 15000 #設置session在redis中的Namespace,避免和其他key沖突 spring.session.redis.namespace=spring:session 配置redis的鏈接 spring.redis.host=localhost spring.redis.password= spring.redis.port=6379
到這裏,其實已經配置好了,可以直接使用httpsession了,沒有特別的地方。
開發過程遇到的問題。
本地測試通過之後部署到測試環境發現無法正常運行,報如下異常:
Caused by: io.lettuce.core.RedisCommandExecutionException: ERR unknown command ‘CONFIG‘ at io.lettuce.core.protocol.AsyncCommand.completeResult(AsyncCommand.java:118) ~[lettuce-core-5.0.3.RELEASE.jar:na] at io.lettuce.core.protocol.AsyncCommand.complete(AsyncCommand.java:109) ~[lettuce-core-5.0.3.RELEASE.jar:na] at io.lettuce.core.protocol.CommandHandler.complete(CommandHandler.java:601) ~[lettuce-core-5.0.3.RELEASE.jar:na] at io.lettuce.core.protocol.CommandHandler.decode(CommandHandler.java:559) ~[lettuce-core-5.0.3.RELEASE.jar:na] at io.lettuce.core.protocol.CommandHandler.channelRead(CommandHandler.java:511) ~[lettuce-core-5.0.3.RELEASE.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) ~[netty-transport-4.1.23.Final.jar:4.1.23.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) ~[netty-transport-4.1.23.Final.jar:4.1.23.Final] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) ~[netty-transport-4.1.23.Final.jar:4.1.23.Final] at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86) ~[netty-transport-4.1.23.Final.jar:4.1.23.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) ~[netty-transport-4.1.23.Final.jar:4.1.23.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) ~[netty-transport-4.1.23.Final.jar:4.1.23.Final] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) ~[netty-transport-4.1.23.Final.jar:4.1.23.Final] at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86) ~[netty-transport-4.1.23.Final.jar:4.1.23.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) ~[netty-transport-4.1.23.Final.jar:4.1.23.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) ~[netty-transport-4.1.23.Final.jar:4.1.23.Final] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) ~[netty-transport-4.1.23.Final.jar:4.1.23.Final] at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434) ~[netty-transport-4.1.23.Final.jar:4.1.23.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) ~[netty-transport-4.1.23.Final.jar:4.1.23.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) ~[netty-transport-4.1.23.Final.jar:4.1.23.Final] at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965) ~[netty-transport-4.1.23.Final.jar:4.1.23.Final] at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) ~[netty-transport-4.1.23.Final.jar:4.1.23.Final] at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:645) ~[netty-transport-4.1.23.Final.jar:4.1.23.Final] at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580) ~[netty-transport-4.1.23.Final.jar:4.1.23.Final] at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497) ~[netty-transport-4.1.23.Final.jar:4.1.23.Final] at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459) ~[netty-transport-4.1.23.Final.jar:4.1.23.Final] at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:886) ~[netty-common-4.1.23.Final.jar:4.1.23.Final] at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.23.Final.jar:4.1.23.Final] at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_171]
在github上有相關的issue,https://github.com/spring-projects/spring-session/issues/124,並且給了解決辦法。
一般是因為安全問題redis服務端禁用了CONFIG命令,而RedisHttpSessionConfiguration需要使用這個命令進行一些初始化。導致無法初始化。
一個簡單的解決方式是添加一個jiava配置
@Bean public static ConfigureRedisAction configureRedisAction() { return ConfigureRedisAction.NO_OP; }
spring boot 中使用redis session