1 : 스프링 세션 소개
1. 소개
세션은 항상 클러스터를 수행 할 때 해결 해야하는 어려운 문제였습니다. 과거에는 오픈 소스 서블릿 컨테이너-톰카가 제공하는 Tomcat-Redis-Session-Manager 및 Memcached-Session-Manager와 같은 서블릿 컨테이너에서 해결할 수 있습니다.
또는 nginx와 같은로드 밸런싱 및 특정 서버로 라우팅을 통해 IP_HASH를 수행하십시오.
그러나 두 방법 모두 단점이 있습니다.
스프링 세션은 봄의 프로젝트입니다. 서블릿 컨테이너에서 구현 한 httpsession을 스프링 세션으로 대체하여 세션 관리 문제를 해결하는 데 중점을 둡니다. 응용 프로그램에 빠르고 원활하게 통합 될 수 있습니다.
2. 지원 기능
1) 타사 스토리지 컨테이너에 세션을 쉽게 저장합니다. 이 프레임 워크는 Redis, JVM Map, Mongo, Gemfire, Hazelcast, JDBC 및 세션을 저장하기위한 기타 컨테이너를 제공합니다.
2) 동일한 브라우저와 동일한 웹 사이트는 여러 세션 문제를 지원합니다.
3) RESTFULAPI는 쿠키에 의존하지 않습니다. jessionid는 헤더를 통해 전달 될 수 있습니다
4) WebSocket과 Spring-Session을 결합하여 수명주기 관리를 동기화합니다.
3. 통합 방법
통합 방법은 매우 간단합니다. 샘플을 살펴보고 공식 웹 사이트의 가이드를 살펴보십시오. http://docs.spring.io/spring-session/docs/1.3.0.release/reference/html5/
주로 다음과 같은 통합 단계로 나뉩니다.
1) 종속성 JAR 패키지를 소개합니다
2) Redis의 XML 구성 방법과 같은 특정 스토리지 컨테이너에 대한 스토리지 방법을 구성하는 주석 방법 또는 XML 방법
<Context : Annotation-Config/>/** 모든 스프링 세션 준비 초기화를 초기화하고 SpringsessionFilter를 IOC **/<beanclass = "org.springframework.session.data.redis.config.annotation.web.http.redishttpessessionconfiguration"/> ** 링크 컨텐츠에 대한 링크 풀입니다. <beanclass = "org.springframework.data.redis.connection.lettuce.lettuceConnectionFactory"/>
3) XML 메소드에서 web.xml을 구성하고 SpringsessionFilter를 필터 체인으로 구성하십시오.
<filter> <filter-name> springsessionRepositoryFilter </filter-name> <filter-class> org.springframework.wilter.delegatingfilterproxy </filter-class> </filter> <filter-mapping> <filter-name> SpringsessionRitorityFilter </urlter-nit>/*/* <spatcher> 요청 </dispatcher> <spatcher> 오류 </dispatcher> </filter-mapping>
둘 : 스프링 세션 프레임 워크의 내부 분석
1. 프레임 고급 추상 구조 다이어그램
2. Spring-Session은 Servlet Request 및 Redis Storage 관련 문제를 다시 작성합니다
스프링 세션의 일반적인 원칙은 애플리케이션 서버의 요청을 완벽하게 대체합니다.
1. 필터를 사용자 정의하고 도필터 방법을 구현하십시오
2. httpservletrequestwrapper 및 httpservletresponsewrapper 클래스를 상속하고 getsession 및 기타 관련 메소드를 무시합니다 (관련 세션 스토리지 컨테이너 작동 클래스는이 방법에서 호출됩니다).
3. 첫 번째 단계의 도필터 단계에서, 두 번째 단계의 요청 및 응답 클래스. 필터 체인에 별도로 전달하십시오
4. 필터를 필터 체인의 첫 번째 위치로 구성
/**이 클래스는 스프링 세션의 1.30 소스 코드이며, 위의 첫 번째 ~ 세 번째 단계를 구현하는 핵심 클래스이기도합니다. **/public class sessionrepository filter <s Expiringsession <s 확장> 한 번도 requestFilter {/** 세션 스토리지 컨테이너 인터페이스, Redis, MongoDB, Genfire 및 기타 데이터베이저이 인터페이스를 구현합니다. Private ServletContext ServletContext; /** sessionID 전달 인터페이스. 현재 스프링 세션에는 두 개의 구현 클래스가 제공됩니다. **/ private multihttpsessionstrategy httpssessionstrategy = new CookiehttpsessionsTrategy (); public sessionRepositoryFilter (SessionRepository <SSESSIONREPOSITORITORITION) {if (SessionRepository == NULL) {Throw New New OregalArgumentException ( "SessionRepository가 NULL이 될 수 없음"); } this.sessionrepository = sessionrepository; } public void sethttpsessionstrategy (httpssessionstrategy httpssessionstrategy) {if (httpssessionstrategy == null) {throw new new OregalArgumentException ( "httpssessionstrategy가 null이 될 수 없음"); } /** 이전의 스프링 세션 기능 소개를 통해 스프링 세션은 단일 브라우저에서 여러 세션을 지원할 수 있으며, 이는 MultiHttpSsessionsTrateGyAdapter를 통해 달성됩니다. 각 브라우저에는 sessionID가 있지만이 SessionID는 여러 별칭이 있습니다 (브라우저 탭에 따라). 예를 들어, 별칭 1 sessionId alias 2 sessionId ... 그리고이 별칭은 URL을 통해 전달됩니다. 이것은 단일 브라우저 **/ this.httpsessionstrategy = new multihttpssessionstrategyadapter (httpssessionstrategy)에 의한 여러 세션의 원칙입니다. } public void sethttpsessionstrategy (multihttpssessionstrategy httpssessionstrategy) {if (httpssessionstrategy == null) {throw new new OppalargumentException ( "httpssessionstrategy가 null이 될 수 없다"); } this.httpsessionstrategy = httpsessionstrategy; } /**이 방법은 Dofilter를 다시 쓰는 것과 동일하지만 Spring-Session에는 또 다른 캡슐화 계층이 있습니다. 이 방법에서 사용자 정의 요청 및 응답을 작성한 다음 필터 체인 FilterChain **/ @override Protected void dofilterinternal (httpservletrequest request, httpservletreponse responsk, filterchain filterchain)에 전달하십시오. servletexception, ioexception (session_repositoration) (session_repositoration); /** ServletRequest 스프링 세션에 의해 다시 작성되었습니다. 이 클래스는 httpservletRequestWrapper **/ sessionRepositoryRequestWrapper rappedRequest = new SessionRepositoryRequestWrapper (요청, 응답, this.servletContext)를 상속합니다. SessionRepositoryResponseWrapper 줄무늬 응답 = 새로운 SessionRepositoryResponseWrapper (WrappedRequest, Response); httpservletrequest rattoryrequest = this.httpssessionstrategy.wrapRequest (WrappedRequest, WrappedResponse); httpservletResponse StrategyResponse = th리 { /** chain에 사용자 정의 요청과 응답을 전달하십시오. Spring-SessionFilter가 필터 체인의 첫 번째에 위치한 다음 후속 필터와 마지막 제어 계층에 도달하여 얻은 요청 및 응답이 있다고 상상해보십시오. **/ FilterCain.dofilter (StrategyRequest, StrategyResponse); } 마침내 {wrappedRequest.commitsession (); }} public void setservletcontext (servletContext servletContext) {this.ServletContext = servletContext; } / ** 재 작성 된 서블릿 응답 클래스* / 개인 최종 클래스 세션 리포지토리 리포피치 responswrapper 확장 oncommittedResponseWrapper {private final sessionRepositoryRequestWrapper 요청; SessionRepositoryResponseWrapper (SessionRepositoryRequestWrapper 요청, httpservletResponse 응답) {super (응답); if (request == null) {새로운 불법 불법 행정 exception ( "요청이 null이 될 수 없음"); } this.request = 요청; } /**이 단계는 세션을 스토리지 컨테이너로 유지하는 것입니다. 제어 계층에서 세션의 작동 방법을 여러 번 호출 할 수 있습니다. 세션의 각 작업이 스토리지 컨테이너에 지속되면 성능에 영향을 미칩니다. 예를 들어, Redis는 전체 제어 계층을 실행할 수 있고 응답은 정보를 브라우저로 반환하면 응답이 정보를 브라우저에 반환 할 때만 세션이 지속됩니다. **/ @override protected void onresponsecommitted () {this.request.commitsession (); }} /** 요청 클래스의 스프링 세션 클래스는 거의 가장 중요한 재 작성 클래스입니다. Getsession, Session 및 기타 방법과 같은 방법 및 클래스 */ Private Final Class SessionRepositoryRequestWrapper와 같은 메소드를 다시 작성했습니다. Private Boolean requestsessionInvalidated; 개인 최종 HttpservletResponse 응답; 개인 최종 ServletContext ServletContext; Private SessionRepositoryRequestWrapper (HttpserVletRequest 요청, httpservletResponse 응답, ServletContext ServletContext) {Super (요청); this.response = 응답; this.servletcontext = servletcontext; } /** * httpsSessionsTrategy를 사용하여 세션 ID를 응답에 작성하고 * 세션을 지속하십시오. */ private void commitsession () {httpssessionWrapper 줄무늬 = getCurrentSession (); if (trappedSession == null) {// 세션 만료, 쿠키 또는 헤더 if (isinValidAteClientsession ()) {sessionRepositoryFilter.httpSsessionStrategy .oninValidatesession (this, this, response); }} else {s session = prappedSession.getSession (); SessionRepositoryFilter.this.sessionRepository.save (세션); if (! isrequestedSessionIdValid () ||! session.getId (). equals (getRequestedSessionId ())) {// 쿠키 또는 헤더를 브라우저로 다시 작성하여 SessionRepositoryFilter.this.httpssessionstrategy.onnewsession (session, this, this.response); }}} @suppresswarnings ( "선택 취소") private httpsessionWrapper getCurrentSession () {return (httpsessionWrapper) getAttribute (current_session_attr); } private void setCurrentSession (httpssessionWrapper currentsession) {if (currentsession == null) {removeAttribute (current_session_attr); } else {setAttribute (current_session_attr, currentsession); }} @suppresswarnings ( "미숙 한") public string changessessionId () {httpsession session = getsession (false); if (session == NULL) {New New ImperalStateException 던지기 ( "세션 ID를 변경할 수 없습니다.이 요청과 관련된 세션은 없습니다."); } // 구현에서 열심히 세션 속성을 가져옵니다. 구현 게으른로드 맵 <string, object> attrs = new Hashmap <String, Object> (); 열거 <String> IATtrNames = session.getAttributeNames (); while (iattrnames.hasmoreElements ()) {String attrname = iattrnames.nextElement (); 개체 값 = session.getAttribute (attrname); atts.put (attrname, value); } sessionRepositoryFilter.this.sessionRepository.delete (session.getId ()); httpsessionWrapper 원본 = getCurrentSession (); setCurrentsession (null); httpsessionwrapper newsession = getsession (); original.setsession (newsession.getSession ()); Newsession.setMaxInactiveInterval (session.getMaxInactiveInterval ()); for (map.entry <string, object> att Object Attvalue = attr.getValue (); Newsession.setAttribute (attrname, attrvalue); } return newsession.getId (); } // 세션이 유효한지 확인 @override public boolean isrequestedSessionIdValid () {if (this.requestedSessionIdValid == null) {String sessionId = getRequestSessionId (); s 세션 = sessionId == null? NULL : GetSession (SessionId); 반환 isrequestedSessionIdValid (세션); } returedssessionIdValid를 반환합니다. } private boolean isrequestedSessionIdValid (s session) {if (this.requestedSessionIdValid == null) {this.requestedSessionIdValid = session! = null; } returedssessionIdValid를 반환합니다. } private boolean isinValidAteClientsession () {return getCurrentSession () == null && this.RequestEdSessionInvalidated; } private s getsession (String sessionId) {// 세션 SESSEM = SESSIONREPOSITIONFILTER.this.SessionRepository .getSession (sessionId)을 기반으로 세션 스토리지 컨테이너에서 세션을 가져옵니다. if (session == null) {return null; } // 세션이 만료 된 세션을 방지하기 위해 세션의 마지막 액세스 시간을 설정합니다. 반환 세션; } /**이 방법이 매우 친숙합니까? 더 친숙한 getsession ()도 아래에 있습니다. 맞습니다. 여기에서 세션 메소드를 다시 구입하십시오 **/@override public httpsessionwrapper getsession (boolean create) {// Fastly Get Session, 이는 첫 번째 수준 캐시와 제 2 레벨 캐시 httpsessionWrapper 전류 사이의 관계로 이해 될 수 있습니다. if (currentsession! = null) {return currentsession; } // httpsSessionStret requestSessionId = getRequestEdSessionId ()에서 sessionId를 얻습니다. if (requestedSessionId! = null && getAttribute (invalid_session_id_attr) == null) {// 스토리지 컨테이너에서 세션을 가져 와서 현재 초기화 속성 s 세션 = getsession (requestssessionId)을 설정합니다. if (session! = null) {this.requestedSessionIdValid = true; currentsession = new httpsessionWrapper (세션, getServletContext ()); currentsession.setNew (false); setCurrentsession (전류); 반환 전류; } else {if (session_logger.isdebugenabled ()) {session_logger.debug ( "ID에 의해 찾은 세션 없음 :이 httpservletRequest에 대한 getsession (false)에 대한 캐싱 결과"); } setAttribute (invalid_session_id_attr, "true"); }} if (! create) {return null; } if (session_logger.isdebugenabled ()) {session_logger.debug ( "새로운 세션이 만들어졌습니다. 세션이 생성 된 위치에 문제를 해결하기 위해 스택 트레이스를 제공했습니다 (오류가 아닙니다)." + session_logger_name에 대한 디버깅에 대한 로그를 사용하지 않으면 (새로운 runtimeex, 새로운 runtimeex x)를 방지 할 수 있습니다. 오류) "); } // 브라우저 또는 기타 HTTP 방문자가 서버에 처음으로 액세스하는 경우, 새 세션 세션을 작성하십시오. session.setLastAccessedTime (System.CurrentTimeMillis ()); currentsession = new httpsessionWrapper (세션, getServletContext ()); setCurrentsession (전류); 반환 전류; } @override public servletcontext getServletContext () {if (this.ServletContext! = null) {return this.ServletContext; } // servlet 3.0+ return super.getServletContext (); } @override public httpsessionwrapper getsession () {return getsession (true); } @override public string getRequestedSessionId () {return sessionRepositoryFilter.this.httpsSessionStrategy .getRequestedSessionId (this); } / ** httpsession의 클래스를 다시 작성* / 개인 최종 클래스 httpsessionWrapper는 expiringsessionhttpsession <S> {httpSsessionWrapper (s session, servletContext servletContext) {super (session, servletContext); } @override public void invalidate () {super.invalidate (); SessionRepositoryRequestWrapper.this.requestedSessionInvalidated = true; setCurrentsession (null); SessionRepositoryFilter.this.sessionRepository.delete (getId ()); }}}}요약
위는 스프링 세션의 도입 및 구현 원리의 소스 코드 분석에 대한이 기사의 모든 내용입니다. 모든 사람에게 도움이되기를 바랍니다. 관심있는 친구는이 사이트의 다른 관련 주제를 계속 참조 할 수 있습니다. 단점이 있으면 메시지를 남겨주십시오.