플레이데이터 - 37일차 Spring Boot Framework(2)

Kim Hyen Su·2023년 8월 22일

🌟로깅 라이브러리-Logback

✅로깅이란?

  • 애플리케이션이 동작하는 동안 시스템의 상태나 동작 정보를 시간순으로 기록하는 것을 의미함.

  • 디버깅하거나 개발 이후 발생한 문제를 해결할 때 원인을 분석하는데 꼭 필요한 요소.

  • 자바 진영에서 가장 많이 사용되는 로깅 프레임워크는 LogBack 이다.

✅Logback이란?

  • log4j 이후에 출시된 로깅 프레임워크로서 slf4j를 기반으로 구현되었으며, 성능이 좋다.

  • 또한, spring-boot-starter-web 라이브러리 내부에 내장되어 있어 별도의 의존성을 추가하지 않아도 사용이 가능하다.

  • Logback 특징

  1. 로그 레벨은 5개로 설정 가능하다.
    • ERROR : 로직 수행 중에 시스템에 심각한 문제가 발생해서 애플리케이션의 작동이 불가능한 경우를 의미.
    • WARN : 시스템 에러의 원인이 될 수 있는 경고 레벨을 의미.
    • INFO : 애플리케이션의 상태 변경과 같은 정보 전달을 위해 사용.
    • DEBUG : 애플리케이션의 디버깅을 위한 메시지를 표시하는 레벨을 의미.
    • TRACE : DEBUG 레벨보다 더 상세한 메시지를 표현하기 위한 레벨을 의미.
  2. 실제 운영 환경과 개발 환경에서 각각 다른 출력 레벨을 설정해서 로그 확인 가능.
  3. Logback의 설정 파일을 일정시간마다 스캔해서 애플리케이션을 재가동 하지 않아도 설정을 변경할 수 있다.
  4. 별도의 프로그램 지원 없이도 자체적으로 로그 파일을 압축할 수 있다.
  5. 지정된 로그 파일에 대한 보관 기능 등을 설정해서 관리할 수 있다.

Logback 설정

  • 일반적으로 classpath에 있는 설정 파일을 자동으로 참조하기 떄문에 Logback 설정 파일은 리소스 폴더 안에 생성함.

  • logback-spring.xml 파일 생성 및 설정 추가.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <property name="LOG_PATH" value="/.log/"/>

    <!-- Appenders-->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <encoder>
            <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %logger %msg%n</pattern>
        </encoder>
    </appender>

    <appender name="INFO_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <file>${LOG_PATH}/info.log</file>
        <append>true</append>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <filterNamePattern>${LOG_PATH}/info_${type}.%d{yyyy-MM-dd}.gz</filterNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %logger %msg%n</pattern>
        </encoder>
    </appender>

    <!-- TRACE > DEBUG > INFO > WARN > ERROR > OFF-->
    <!-- Root Logger-->
    <root level="INFO">
        <appender-ref ref="console"/>
        <appender-ref ref="INFO_LOG"/>
    </root>
</configuration>
  • Logback 설정에서 가장 중요한 Appender 영역과 Root 영역이 있다.

Appender 영역

  • 로그의 형태를 설정하고 어떤 방법으로 출력할지 설정하는 영역.
  • Appender는 하나의 인터페이스로 이를 구현한 구현체가 여러개 존재한다.
    • ConsoleAppender : 콘솔에 로그 출력.
    • FileAppender : 파일에 로그 저장.
    • RollingFileAppender : 여러 개의 파일을 순회하면서 로그를 저장.
    • SMTPAppender : 메일로 로그를 전송.
    • DBAppender : DB에 로그를 저장.
  • class 요소로 각 구현체를 정의함.
  • filter 요소로 Appender가 어떤 레벨로 로깅할지 지정.
    • 지정한 레벨 하위의 요소들은 전부 출력해준다.
    • Ex) INFO 지정 → ERROR, WARN, INFO 까지 로그 출력.
  • encoder 요소를 통해 로그의 표현 형식을 패턴으로 정의.

Root 영역

  • 설정 파일에 정의된 Appender를 활용하려면 Root 영역에서 Appender를 참조해서 로깅 레벨을 설정함.
  • 만약, 특정 패키지에 대해 다른 로깅 레벨을 설정하고 싶은 경우, root 대신하여 logger를 사용해 지정이 가능하다.
<logger name="com.springboot.api.controller" level="DEBUG" additivity="false">
	<appender-ref ref="console"/>
    <appedner-ref ref="INFO_LOG"/>
</logger>
  • name 속성으로 패키지 단위로 로깅이 적용될 범위를 지정.
  • level 속성으로 로그 레벨을 지정.
  • additivity 속성으로 앞에서 지정한 패키지 범위에 하위 패키지를 포함할지 여부를 지정.(default : true)

Logback 적용하기

  • Controller 내부 메서드에 아래 코드 추가
LOGGER.info("해당 메서드가 호출되었습니다.");
  • 클라이언트로 부터 입력 받은 변수를 로거에 담아서 확인하기 위해 아래 코드 추가.
LOGGER.info("해당 메서드에서 받은 입력 데이터 : {}", 변수명);
  • 중괄호({})는 자동으로 변수값이 포맷팅 되어 로그 메시지가 구성된다.

✅로그를 남기는 방법

System.out.println()의 문제점

  • 로그를 남기기 위한 방법으로 System.out.println() 메서드를 사용한 시스템 로그를 많이 사용한다.
  • 위 방식은 성능저하의 원인이 된다.
  • 콘솔에 로그를 남길경우, 내용이 완전히 저장될 때까지 뒤에 프린트할 내용들에 대기가 발생하게 된다. 이는 시스템 시간에 의존적이기 때문이다.

logback을 이용함으로써 로그 관리가 간편

  • 기존의 로거들은 출력을 위해서 문자열을 더해 전달해줘야 했지만, slf4j는 format 문자열에 중괄호를 사용하여 출력하고자 하는 데이터들을 콤마로 구분하여 전달이 가능하다.

  • 위와 같은 방식을 사용하면 문자열 더하기 연산이 발생하지 않아 성능이 더 좋다.

❓로그로 무엇을 기록해야 할까?

  • 로깅을 설정하고 출력하는 방법을 숙지한 경우, 로그에 어떤 내용을 포함할 지 고민해봐야 한다.

  • 로그에 담길 내용(주과적인 생각)

  1. 오류 사항 해결
    • 해당 문제에 대한 내용은 선제적으로 모니터링하는 것이 아니라, 최종 사용자를 통해 문제에 대해 알게되고 능동적이 아니라 수동적으로 문제를 해결해야 하기 때문에 오류 사항은 로깅이 필요하다.

🌟데이터베이스 연동

  • MySQL 사용

✅ORM

  • Object Relational Mapping 의 약어로서 객체 관계 매핑을 의미함.
  • 객체지향 언어에서 의미하는 객체와 RDB의 테이블을 자동 매핑하는 방법.
  • 자바의 클래스는 RDB에 데이터를 저장하기 위해 만들어진 것이 아니다.(패러다임이 다르다) 따라서, 매핑을 하기 위해 불일치와 제약사항을 해결하는 역할을 해준다.
  • ORM을 사용하면 쿼리문 작성이 아닌 메서드 실행을 통해 데이터 조작이 가능하다.

ORM 장점

  • 데이터베이스 쿼리를 객체지향적으로 조작 가능
    • 쿼리문 작성 양이 줄어 개발 비용 감소.
    • 코드 가독성이 좋아짐.
  • 재사용 및 유지보수가 편리
    • ORM을 통해 매핑된 객체는 모두 독립적으로 작성되어 있어 재사용이 용이하다.
    • 객체들은 각 클래스로 나뉘어 있어 유지보수가 훨씬 수월하다.
  • 데이터베이스에 대한 종속성이 줄어듦.
    • ORM을 통해 자동 생성된 SQL문은 객체를 기반으로 데이터베이스 테이블을 관리하기 때문에 데이터베이스에 종속적이지 않는다.
    • 데이터베이스를 교체하는 상황에서도 비교적 적은 리스크를 부담.

ORM 단점

  • ORM 만으로 온전한 서비스를 구현에 한계가 있음
    • 복잡한 서비스의 경우 직접 쿼리를 구현하지 않고 구현이 어렵다는 한계.
    • ORM만으로 복잡한 쿼리를 설계 없이 구현할 경우, 성능 문제 발생할 수 있음.
  • 애플리케이션의 객체 관점과 데이터베이스의 관계 관점의 불일치가 발생.
    • 세분성 : 클래스가 테이블 수보다 많아질 수 있음.
    • 상속성 : RDBMS에 상속이라는 개념이 없음.
    • 식별성 : RDBMS는 기본키로 동일성을 정의하지만, 자바는 두 객체의 값이 같더라도 다르다고 판단할 수 있음.
    • 연관성 : 객체지향 언어는 객체를 참조하여 연관성을 나타내지만, RDBMS는 외래키를 삽입하여 연관성을 표현함.
      • 또한, 객체 참조 시 방향성이 존재하지만, RDBMS는 양방향의 관계를 가지므로 방향성이 없다.
    • 탐색 : 자바와 RDBMS는 어떤 값에 접근하는 방식이 다르다. 자바는 특정 값을 접근하기 위해 객체 참조 같은 연결 수단을 활용한다. 반면 RDBMS는 쿼리를 최소화하고 조인을 통해 테이블을 여러개 로딩하여 값을 추출하는 방식을 채택.

✅JPA

  • 자바의 ORM 기술 표준으로 채택된 인터페이스의 모음.
  • ORM이 큰 개념이라면, JPA는 구체화된 스펙을 포함.
  • JPA는 실제로 동작하는 것이 아니라 어떻게 동작해야 하는지 메커니즘을 정리한 표준 명세로 생각하면 된다.
  • JPA의 메커니즘을 보면 내부적으로 JDBC를 사용한다.
  • 대표적인 JPA 기반의 구현체
    • 하이버네이트(Hibernate)
    • 이클립스 링크(EclipseLink)
    • 데이터 뉴클리어스(DataNucleus)

✅Hibernate

  • 자바의 ORM 프레임워크로써 JPA가 정의하는 인터페이스를 구현하고 있는 JPA 구현체 중 하나이다.
  • 하이버네이트의 기능을 더욱 편하게 사용하기 위해 모듈화한 Spring Data JPA를 활용하기 때문에 JPA 자체를 직접 사용할 일은 거의 없다.

Spring Data JPA

  • 하이버네이트에서 자주 사용되는 기능을 더 쉽게 사용할 수 있게 구현한 라이브러리.
  • CRUD 처리에 필요한 인터페이스 제공.
  • 엔티티 매니저를 직접 다루지 않고 레포지토리를 정의해 사용함으로써 스프링이 적합한 쿼리를 동적으로 생성하는 방식으로 데이터베이스를 조작함.

✅영속성 컨텍스트

  • 애플리케이션과 데이터베이스 사이에서 엔티티와 레코드의 괴리를 해소하는 기능과 객체를 보관하는 기능을 수행.
  • 영속 객체 : 엔티티가 영속성 컨텍스트로 들어와 JPA의 관리 대상이 된 객체.
  • 영속성 컨텍스트는 세션 단위의 생명주기를 가진다.

엔티티 매니저

  • 엔티티를 관리하는 객체.
  • 데이터베이스에 접근하여 CRUD 작업을 수행.

엔티티 매니저 팩토리

  • 엔티티 매니저를 생성.
  • 애플리케이션 내 단 하나만 생성되며, 모든 엔티티가 공유하여 사용.
  • 하이버네이트에서 persistence.xml 이라는 설정 파일을 구성하여 사용함.

엔티티 생명주기

  • 트랜잭션과 연관하여 생각해보기!!

  • 비영속(New) : 영속성 컨텍스트에 추가되지 않은 엔티티 객체의 상태를 의미.

  • 영속(Managed) : 영속성 컨텍스트에 의해 엔티티 객체가 관리되는 상태.

  • 준영속(Detached) : 영속성 컨텍스트에 의해 관리되던 엔티티 객체가 컨텍스트와 분리된 상태.

  • 삭제(Removed) : 데이터베이스에서 레코드 삭제를 위해 영속성 컨텍스트에 삭제 요청한 상태.

✅데이터베이스 연동

프로젝트 생성

  • 스프링 프로젝트 생성
  • 의존 추가
    • Developer: Lombok, Spring Configuration Processor
    • Web : Spring Web
    • SQL : Spring Data JPA, MySQL Driver
  • Swagger 의존 및 설정 추가(명세 추가)
  • logback-spring.xml 추가(로거 추가)

연동할 데이터베이스 정보 작성(application.properties)

<MySQL 연동>
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot
spring.datasource.username=
spring.datasource.password=

spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
  • spring.datasource.driverClassName : 연동하려는 데이터베이스의 드라이버를 정의.
  • spring.datasource.url : MySQL의 경로
  • spring.datasource.username & password : 계정 정보 기입
  • 하위 설정은 하이버네이트를 사용할 때 활성화할 수 있는 선택사항
  • ddl-auto : 데이터베이스를 자동으로 조작하는 옵션
    • create : 애플리케이션 기동되고 SessionFactory가 실행될 때 기존 테이블을 지우고 새로 생성함.
    • create-drop : create와 동일한 기능을 수행하나 애플리케이션을 종료하는 시점에 테이블을 지움.
    • update : SessionFactory가 실행될 때 객체를 검사해서 변경된 스키마를 갱신한다. 기존에 저장된 데이터는 유지.
    • validate : update처럼 객체를 검사하지만 스키마는 건드리지 않음. 검사 과정에서 데이터베이스의 테이블정보와 객체의 정보가 다르면 에러 발생.
    • none : ddl-auto 기능을 사용하지 않음.
  • 일반적으로 운영환경에서 validate, none 설정 사용하며, 개발 환경에서 create 또는 update를 사용.
  • show-sql : 로그에 하이버네이트가 생성한 쿼리문을 출력하는 옵션.
    • format-sql 옵션으로 가독성이 좋게 포매팅되도록 설정.
profile
백엔드 서버 엔지니어

0개의 댓글