您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關springboot中如何整合spring-session,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
它可以替代 HttpSesession
。而且改動極小,對應用透明。底層可以使用內存,Redis等存儲Session信息。通過Redis
這種方式可以做到Session
共享,在集群環境中所有節點共享Session。
文檔 https://docs.spring.io/spring-session/docs/current/reference/html5/
使用 spring-session-data-redis,一定要先整合redis到項目。
<dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency>
配置類:
RedisSessionProperties
spring: session: timeout: 1800 # session的過期時間,單位是秒 store-type: REDIS # session的存儲類型,枚舉 redis: namespace: "spring:session" # session存儲在redis中的命名空間 flush-mode: IMMEDIATE # 刷出模式,枚舉:ON_SAVE ,IMMEDIATE cleanup-cron: "0 * * * * *" # 定時清理過期session任務的`cron`表達式
關于 spring.session.redis.flush-mode
ON_SAVE
只有當
SessionRepository.save(Session)
方法被調用時, 才會將session中的數據同步到redis中. 在web 應用中, 當請求完成響應后, 才開始同步. 也就是說在執行response 之前session數據都是緩存在本地的。
IMMEDIATE
當執行
SessionRepository.createSession()
時, 會將session數據同步到redis中; 當對session的attribute進行set/remove 等操作時, 也會同步session中的數據到redis中。它是實時同步的
使用并需要修改什么,像平時一樣。獲取到 Servlet的Session就是了。
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @RequestMapping("/test") @Controller public class TestController { @GetMapping("/session") public ModelAndView session(HttpServletRequest request) { HttpSession httpSession = request.getSession(); // 是否新創建的 true System.out.println(httpSession.isNew()); // 實現類 org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper$HttpSessionWrapper System.out.println(httpSession.getClass().getName()); // 寫入數據到session(底層使用redis存儲) httpSession.setAttribute("name", "SpringBoot中文社區"); return new ModelAndView("test/test"); } }
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Test</title> </head> <body> Hello ${name} </body> </html>
默認情況下,客戶端使用Cookie來存儲會話id
Connection: keep-alive Content-Encoding: gzip Content-Language: zh-CN Content-Type: text/html;charset=UTF-8 Date: Thu, 17 Oct 2019 08:57:07 GMT Server: nginx Set-Cookie: PHPSESSIONID=Y2YwMDM1YjctMjBiYy00OWRiLWI5NGItZjFmNDU4ZDcxNThm; Max-Age=36000; Expires=Thu, 17 Oct 2019 18:57:07 GMT; Path=/; HttpOnly; SameSite=Lax Transfer-Encoding: chunked
server: servlet: session: cookie: name: PHPSESSIONID #cookie名稱 domain: # 域 path: # 路徑 comment: # 備注 httpOnly: # 是否僅用于http傳輸 secure: # 是否僅在SSL的情況下傳輸 maxAge: # 生命周期
自定義
CookieSerializer
到IOC。
@Bean public CookieSerializer cookieSerializer() { DefaultCookieSerializer serializer = new DefaultCookieSerializer(); serializer.setCookieName("JSESSIONID"); serializer.setCookiePath("/"); serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$"); return serializer; }
通俗的理解就是,可以建立key和session的索引,根據某些key獲取到session。
需求:根據用戶id,獲取到它的會話
value僅僅接受字符串
@Autowired FindByIndexNameSessionRepository<? extends Session> sessions; .... 代碼省略 Integer userId = user.getId(); // 往session中存入用戶的id信息 request.getSession().setAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, userId + "");
@Autowired FindByIndexNameSessionRepository<? extends Session> sessions; .... 代碼省略 Integer userId = user.getId(); // 返回該用戶的所有的有效session Map<String, ? extends Session> sessions = this.sessions.findByPrincipalName(userId + ""); for (Session session : sessions.values()) { // 根據sessionId刪除 this.sessions.deleteById(session.getId()); }
public interface FindByIndexNameSessionRepository<S extends Session> extends SessionRepository<S> { String PRINCIPAL_NAME_INDEX_NAME =FindByIndexNameSessionRepository.class.getName() .concat(".PRINCIPAL_NAME_INDEX_NAME"); Map<String, S> findByIndexNameAndIndexValue(String indexName, String indexValue); default Map<String, S> findByPrincipalName(String principalName) { return findByIndexNameAndIndexValue(PRINCIPAL_NAME_INDEX_NAME, principalName); } }
可以通過findByIndexNameAndIndexValue
方法自己建立key和session的索引信息。
session過期,銷毀事件依賴于redis的key過期通知。事件對象通過spring的事件訂閱發布機制來發布
SessionCreatedEvent 創建 SessionDestroyedEvent |-SessionExpiredEvent 過期 |-SessionDeletedEvent 刪除(用戶主動 invalidate())
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.session.events.SessionCreatedEvent; import org.springframework.session.events.SessionDeletedEvent; import org.springframework.session.events.SessionExpiredEvent; import org.springframework.stereotype.Component; @Component public class SpringSessionListener { private static final Logger LOGGER = LoggerFactory.getLogger(SpringSessionListener.class); @EventListener(SessionCreatedEvent.class) @Async public void sessionCreatedEvent(SessionCreatedEvent sessionCreatedEvent) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("session 創建:{}", sessionCreatedEvent.getSessionId()); } } @EventListener(SessionExpiredEvent.class) public void sessionExpiredEvent(SessionExpiredEvent sessionCreatedEvent) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("session 到期:{}", sessionCreatedEvent.getSessionId()); } } @EventListener(SessionDeletedEvent.class) public void sessionDeletedEvent(SessionDeletedEvent sessionCreatedEvent) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("session 刪除:{}", sessionCreatedEvent.getSessionId()); } } }
比較麻煩,需要自己通過代碼配置添加
需要添加SessionEventHttpSessionListenerAdapter到ioc, 通過這個bean的構造函數, 添加多個 HttpSessionListener 實現 SessionEventHttpSessionListenerAdapter
SessionEventHttpSessionListenerAdapter(List<HttpSessionListener> listeners)
但是這個Bean其實框架已經自動添加了, 再次添加會導致異常
曲線救國, 從IOC里面讀取到這個bean, 通過反射, 對私有屬性 listeners 添加監聽器
@Configuration public class SpringSessionConfiguration { private static final Logger LOGGER = LoggerFactory.getLogger(SpringSessionConfiguration.class); @Autowired SessionEventHttpSessionListenerAdapter sessionEventHttpSessionListenerAdapter; @PostConstruct public void addHttpSessionListener() { try { Field field = SessionEventHttpSessionListenerAdapter.class.getDeclaredField("listeners"); field.setAccessible(Boolean.TRUE); @SuppressWarnings("unchecked") List<HttpSessionListener> listeners = (List<HttpSessionListener>) field.get(sessionEventHttpSessionListenerAdapter); listeners.add(new SessionListener()); if (LOGGER.isDebugEnabled()) { LOGGER.debug("添加SESSION監聽器"); } } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } } // @Bean //BeanDefinitionOverrideException // public SessionEventHttpSessionListenerAdapter sessionEventHttpSessionListenerAdapter() { // SessionEventHttpSessionListenerAdapter sessionEventHttpSessionListenerAdapter = new SessionEventHttpSessionListenerAdapter(Arrays.asList(new SessionListener())); // return sessionEventHttpSessionListenerAdapter; // } }
默認客戶端使用Cookie來存儲session id。但是對于一些客戶端來說,cookie不一定方便,可以通過 http header來攜帶cookie的id。
實現類 CookieHttpSessionIdResolver
使用Cookie(默認) HeaderHttpSessionIdResolver
使用Header
@Bean public HttpSessionIdResolver httpSessionIdResolver() { return HeaderHttpSessionIdResolver.xAuthToken(); // 使用 X-Auth-Token 解析Cookie }
HeaderHttpSessionIdResolver 還支持自定義header的名稱,代碼及簡單,可以自己閱讀學習。
spring:session:expirations:1570672200000 spring:session:index:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:1 spring:session:sessions:d82bf2bb-deb3-474c-89bb-96c2bfa646c4 spring:session:sessions:expires:94b2ce1f-053e-4c20-a8b7-f4d69102a114
上述就是小編為大家分享的springboot中如何整合spring-session了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。