Spring REST API에서 세션에 정보 저장 (2) with Spring Session

0

프로젝트

목록 보기
6/14

Spring REST API에서 세션에 정보 저장 1편 보러가기

들어가기에 앞서

마이크로서비스 아키텍처 관련 연구를 진행하면서 고민했던 점이 하나 있다.

"단일 모듈로 이루어진 웹 앱의 세션을 마이크로서비스들로 쪼개면 어떻게 사용하지?"

이를 위한 기술로 Spring session을 이용할 수 있다고 한다. 원래 웹 서버 내에 존재하는 세션을 외부 저장소로 옮기는 것이다. 이 때 외부 저장소로는 jdbc, mongoDB, 그리고 Redis와 같은 것들이 있을 수 있다.

1편에서의 세션은 톰캣 내부의 세션을 이용하는 방식이다. 그러나 다중 서버를 사용할 경우 이 세션은 역시 공유되지 않을 수 있다.

따라서 Spring session과 같은 것을 이용해 세션 공간을 외부 저장소로 옮길 수 있다. 1편에서 고민해결을 위해 으쌰으쌰 하던 분 역시 Spring session을 이미 사용중이었다. 그러나 사용 방식에 있어 크게 달라진 점은 없다!! 본 게시글에서는 Spring-session-jdbc를 사용하는 방식에 대해 서술해본다.

1. 의존성 설정

		<dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-jdbc</artifactId>
            <version>3.2.1</version>
        </dependency>

나의 프로젝트는 Maven 프로젝트를 기준으로 하기 때문에 gradle을 사용한다면 문법이 조금 다를 수 있다.

먼저 spring-session-jdbc 의존성을 추가해준다. 나는 시놀로지의 mariaDB를 사용할 것이기 때문에 mariaDB connector도 의존성을 추가해야한다. mysql을 사용한다면 jdbc-connector를 추가하면 된다.

		<dependency>
            <groupId>org.mariadb.jdbc</groupId>
            <artifactId>mariadb-java-client</artifactId>
            <version>3.3.2</version>
        </dependency>

또 db안에 spring session이 자동적으로 테이블을 만들어주기 위해서는 jpa설정이 필요하기 때문에 관련 의존성도 추가해준다.

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <version>3.1.4</version>
        </dependency>

application.properties 설정

마찬가지로, .properties 파일 외에 .yml 파일을 사용한다면 문법이 조금 다를 수 있다. 그러나 큰 차이는 없다!!
오히려 yml이 더 편한 것 같다 ㅠㅠ

spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.url=jdbc:mariadb://{db주소 (기본적으로 localhost:3306)}/{db명}
spring.datasource.username={db id}
spring.datasource.password={db password}
// 만료시간
spring.session.timeout=600
spring.session.store-type=jdbc
spring.session.jdbc.initialize-schema=always
// 세션 테이블 이름
spring.session.jdbc.table-name=SPRING_SESSION
spring.jpa.defer-datasource-initialization=true
spring.jpa.open-in-view=false
// 테이블을 자동적으로 만들어줌
spring.jpa.generate-ddl=true

먼저 두 번째 줄에서 db주소와 세션 저장소로 사용할 데이터베이스를 지정해준다. 이미 프로젝트용으로 사용하고 있는 DB가 있다면 해당 DB 명을 적어주면된다. 어짜피 세션용으로 테이블이 자동적으로 생성된다.

그 외 설정은 단순하다. 설정이 완료되면 웹 앱 실행시에 세션용 테이블이 없다면 생성된다.

SPRING_SESSION 테이블에는 생성된 세션들이 등록된다.
SPRING_SESSION_ATTRIBUTES 테이블에는 특정 세션 id에 저장된 attribute들이 담긴다!

컨트롤러 설정

Session 생성 컨트롤러

1편에서와 마찬가지로 똑같다. 그 대신 세션이 톰캣 세션이 아니라 spring session에서 설정해둔 외부 저장소가 된다.

	@PostMapping("/session_create")
    public Map<String, Object> createSession(@RequestBody Person req, HttpSession session) {
        Map<String, Object> data = new HashMap<>();

        session.setAttribute("user", req);

        data.put("sessionId", session.getId());

        return data;
    }

마찬가지로 코드는 달라진 바가 없다. 그러나 /session_create로 요청을 보내면 테이블에 정보가 담긴다!! 아래는 테이블에 담긴 정보를 보여주는 사진이다.

Session에 담긴 내용 조회와 만료 컨트롤러

	@GetMapping("/session_check")
    public Map<String, Object> checkSession(HttpSession session) {
        Map<String, Object> data = new HashMap<>();

        Person user = new Person();

        Object obj = session.getAttribute("user");

        if (obj instanceof Person) {
           user = (Person) obj;
        }

        data.put("name", user.getUid());

        return data;
    }

    @GetMapping("/session_destroy")
    public Map<String, Object> destroySession(HttpSession session) {
        Map<String, Object> data = new HashMap<>();

        data.put("result", "success");

        session.invalidate();

        return data;
    }

마찬가지로 크게 달라진 점이 없다. /session_check에서는 담겨있는 user를 Object로 불러와서 타입이 Person이면 Person 객체에 옮겨 담고 해당 객체로부터 정보를 가져온다.

/session_destroy 에서는 현재 열려있는 세션을 만료시키고 종료한다. 이 경우에 테이블에서도 세션 정보가 사라지는 것을 확인할 수 있다!

외부 저장소에 담을 객체

public class Person implements Serializable {

    private static final long serialVersionUID = 8986544052015350952L;
    
    private String uid;

	...
}

기본적으로 직렬화를 거쳐 저장되어야 하므로 Serializable이 필수적이다. 그리고 serialVersionUID 역시 필수적인데, 해당 클래스의 객체라는 것을 표시해준다고 생각하면된다. 우리로 따지면 주민번호? 같으 개념이다.
이걸 따로 지정하지 않으면 랜덤으로 컴파일 과정에서 랜덤으로 주어지는데, 직렬화를 하여 저장할 때의 객체와 역직렬화를 통해 다시 불러온 객체의 시리얼UID가 다르면 서로 다른 객체로 보기 때문에 문제가 생길 수 있다. 따라서 아무 값이나 지정해주면 된다!!

소감

음... 일단 Spring session은 정말 편한 기술인 것 같다. 기본적으로 톰캣 세션에 무엇을 담으면 내가 눈으로 세션을 확인할 수 없다. 그래서 뭐가 담겨있는지 알기가 어렵다.

그러나 외부 저장소로 옮겨놓으면 세션에 뭐가 담기는지 일일히 확인이 가능하다. 그리고 웹 서버를 여러개 사용하더라도 같은 세션을 공유할 수 있다는 점에서 큰 이점이 있는 것 같다. 특히 내가 연구하는 분야의 마이크로서비스에서는 이와 같은 기술을 이용해서 기존 단일 모듈에서의 세션이라는 개념을 그대로 가지고 갈 수 있다는 장점이 있다.

만약 마이크로서비스에서 세션을 공유하지 못한다면, 단일 모듈에서 마이크로서비스로 전환하는 과정에서 세션에 담긴 정보 역시 주고 받는 식으로 마이크로서비스들 간 통신이 이루어져야하는데 이는 엄청나게 많은 정보들이 왔다갔다 할 수도 있다. 이것은 불필요한 일이다..

profile
최악의 환경에서 최선을 다하기

0개의 댓글