Open Session In View: 하이버네이트

Open Entity Manager In View: JPA

관례상 OSIV라고 한다.

 

 

Spring.Jpa.open-in-view는 기본값이 true로 되있으며 이 전략은 최초 DB 커넥션 시작 지점부터 API응답이 끝날 때 까지 영속성 컨텍스트와 데이터베이스 커넥션을 유지하는 것이다.  지연 로딩을 하기 위해서는 영속성 컨텍스트가 살아 있어야 하고, 또 영속성 컨텍스트는 기본적으로 DB 커넥션을 유지하기 때문에 이 전략을 사용하게 되면  View Template와 API 컨트롤러는 지연로딩이 가능하다.

 

하지만 이 전략은 단점이 오랜기간 DB커넥션 리소스를 사용하기에 만약 트래픽이 몰리게 된다면 커넥션이 모자라 장애가 생성된다.

 

그래서 이러한 상황을 막기 위한 전략이다

Spring.Jpa.open-in-view를 false로 설정하게 되면 OSIV가 종료되며 트랜잭션이 끝날 때 영속성 컨텍스트는 닫고 DB커넥션은 반환된다. 그래서 위와 같은 상황에 커넥션 리소스가 낭비되는 일은 없다.

하지만 OSIV가 종료되면 모든 지연 로딩은 저 트랜잭션 범위내에서 해결해야하기에 지연 로딩코드를 트랜잭션 안으로 넣어야 하며 view template에서 지연로딩은 동작하지 않는다. 결국 트랜잭션이 끝나기 전에 강제로 지연로딩을 호출해 두어야 한다.

 

그래서 나온 방법이 Command와 Query를 분리하는 방법이다.

비즈니스 로직은 엔티티 몇개를 등록 및 수정하는 정도라 성능에 문제가 되지 않지만 조회하여 복잡한 화면을 출력하기 위한 쿼리는 성능을 최적화 하는것이 중요하다.

그래서 이 두가지를 명확하게 분리하는 선택은 유지보수 관점에서 의미있다.

 

만약 수정과 등록 등의 핵심비즈니스 로직을 OrderService라 하면

화면 또는 API에 맞춰야 하는 서비스는 OrderQueryService처럼 작성할 수 있다.(주로 읽기 전용 트랜잭션을 사용한다.)

보통은 서비스 계층에서 트랜잭션을 유지하며 두 서비스 모두 트랜잭션을 유지하면서 지연 로딩을 사용할 수 있다.

 

이때 마이크로서비스  아키텍쳐를 사용한다 하면 사용자들이 많이 사용하는 서비스는 OSIV를 끄고

ADMIN과 같은 관리자 페이지는 OSIV를 켜서 사용하는 것 처럼 설정을 각각 지정하여 서비스가 가능하다. 

 

 

 

 

출처

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-JPA-API%EA%B0%9C%EB%B0%9C-%EC%84%B1%EB%8A%A5%EC%B5%9C%EC%A0%81%ED%99%94/dashboard

 

실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화 - 인프런 | 강의

스프링 부트와 JPA를 활용해서 API를 개발합니다. 그리고 JPA 극한의 성능 최적화 방법을 학습할 수 있습니다., - 강의 소개 | 인프런

www.inflearn.com

 

'Spring' 카테고리의 다른 글

[SpringBoot] @MappedSuperclass  (0) 2023.05.21
[Java] Stream이란?  (0) 2023.05.14
[SpringBoot] 싱글톤(Singleton) 이란?  (0) 2023.05.12
[java] Dependency Injection 개념  (0) 2023.05.11
[SpringSecurity] AccessDeniedHandler  (0) 2023.05.09

객체의 입장에서 공통 매핑 정보가 필요할 때 사용한다.

공통적으로 사용되는 필드들을 별도의 클래스로 추출하고, 이를 상속하는 엔티티 클래스들이 이를 재사용할 수 있도록 하기 위해 사용한다.

 

예시 코드)

@MappedSuperclass
public abstract class BaseEntity {

    @Column(name = "created_at")
    private LocalDateTime createdAt;

    @Column(name = "updated_at")
    private LocalDateTime updatedAt;

}

@Entity
public class SomeEntity extends BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

}

 

 

이런식으로 @MappedSuperclass를 사용하면, 코드의 중복을 줄이고 관리 포인트를 한 곳에서 관리할 수 있어 효율적인 코드 관리가 가능하다.

 

다만  이 어노테이션은 상속관계 매핑이 아니며, 지정된 클래스는 엔티티가 아니기 때문에, JPA의 엔티티 매니저를 통해 직접 조회 및 저장등의 DB연산을 수행할 수 없다.

 

직접 생성해서 사용할 일은 없기때문에 추상 클래스로 만드는 것이 좋다. 

 

@EntityListener와 @PrePersist, @PreUpdate등의 Jpa 이벤트 어노테이션은 이 어노테이션이 지정된 클래스에서는 동작하지 않으므로 이를 사용하기 위해서는 실제 엔티티 클래스에서 사용해야한다.

'Spring' 카테고리의 다른 글

[JPA] OSIV 와 성능 최적화  (0) 2023.06.08
[Java] Stream이란?  (0) 2023.05.14
[SpringBoot] 싱글톤(Singleton) 이란?  (0) 2023.05.12
[java] Dependency Injection 개념  (0) 2023.05.11
[SpringSecurity] AccessDeniedHandler  (0) 2023.05.09

Stream 이란?

 

Java8 부터 지원하는 Stream은 컬렉션, 배열등에 대해 저장되어 있는 요소들을 하나씩 참조하며 반복적인 처리를 하는 기능이다.

Stream이용 시 불필요한 for문과 그안에서 이루어 지는 if문 등의 분기 처리를 쓰지 않고 깔끔하고 직관적인 코드로 변경가능하다.

 

Stream특징

  1. Stream은 원본 데이터로 부터 데이터를 읽기만 할 뿐, 원본 데이터 자체를 변경하지 않는다
  2. Steam은 한 번 사용하면 닫혀서 재사용이 불가능하다. 필요하다면 정렬된 결과를 컬렉션이나 배열에 담아 반환할 수 있다.
  3. Stream은 작업을 내부 반복으로 처리하며 Stream을 이용한 작업이 간결할 수 있는 비결 중 하나이다. 내부 반복이라는 것은 반복문을 메서드의 내부에 숨길 수 있다는 것을 의미한다(코드상 반복문이 노출되지 않는다)

 

Stream 구조

Stream의 구조는 크게 세가지로 볼 수 있다.

  1. Stream 생성
  2. 중개 연산
  3. 최종 연산

세가지로 구성되며 중개연산은 연산 결과를 Stream 형태로 반환하기 때문에 연속적으로 연결해서 사용할 수 있다.

정리하자면 데이터소드객체집합.Stream생성().중개연산().최종연산(); 이다.

 

Stream 생성

 

Stream API는 다음과 같은 다양한 데이터 소스에서 생성이 가능하다.

  1. 컬렉션
  2. 배열
  3. 가변 매개변수
  4. 지정된 범위의 연속된 정수
  5. 특정 타입의 난수들
  6. 람다 표현식
  7. 파일
  8. 빈 스트림

 

중개연산

 

중개연산은 Stream을 전달 받아 Stream으로 반환하므로 중개 연산을 연속으로 사용이 가능하다.

또한 Stream의 중개연산은 필터-맵(filter-map)기반의 API를 사용함으로써 지연(Lazy)연산을 통해 최적화가 가능하다.

대표적인 중개 연산과 그에 따른 메소드는 다음과 같다.

  1. Stream 필터링: filter(), distinct()
  2. Stream 변환: Map(), flatMap()
  3. Stream 제한: limit(), skip()
  4. Stream 정렬: sorted()
  5. Stream 연산 결과 확인 : peek()

대표적인 중계 연산 메소드

메소드 설명
Stream<T> filter(Predicate<? super T> predicate) 해당 스트림에서 주어진 조건(predict)에 맞는 요소만으로 구성된 새로운 스트림을 반환한다
<R> Stream<R>map(Function<? super T, ?extends R> 
mapper
해당 스트림의 요소들을 주어진 함수에 인수로 전달하여, 그 반환값으로 이루어진 새로운 스트림을 반환한다
<R>Stream<R>flatMap(Function<? super,T,>
extends Stream<? extends R>> mapper)
해당 스트림의 요소가 배열일 경우, 배열의 각 요소를 주어진 함수에 인수로 전달하여, 그 반환값으로 이루어진 새로운 스트림을 반환한다
Stream<T> distinct() 해당 스트림에서 중복된 요소가 제거된 새로운 스트림을 반환한다 내부적으로 Object클래스의 equals() 메소드를 사용한다
Stream<T> limit(long maxSize) 해당 스트림에서 전달된 개수만큼의 요소만으로 이루어진 새로운 스트림을 반환한다
Stream<T> peek(Consumer<? super T> action 결과 스트림으로부터 각 요소를 소모하여 추가로 명시된 동작을 수행하여 새로운 스트림을 생성하여 반환한다
Stream<T>skip(long n) 해당 스트림의 첫 번째 요소부터 전달된 개수만큼의 요소를 제외한 나머지 요소만으로 이루어진 새로운 스트림을 반환한다
Stream<T>sorted()
Stream<T>sorted(Comparator<? super T> comparator)
비교자를 전달하지 않으면 영문사전 순으로 정렬한다
해당 스트림을 주어진 비교자를 이용하여 정렬한다


최종연산

 

최종연산은 앞서 중개 연산을 통해 만들어진 stream에 있는 요소들에 대해 마지막으로 각 요소를 소모하여 최종결과를 표시한다.

즉 지연되어있던 모든 중개연산들이 최종 연산 시에 모두 수행되는 것이다. 이렇게 최종 연산 시에 모든요소를 소모한 해당 stream은 더이상 사용이 불가능하다

 

대표적인 최종연산

  1. 요소의 출력: forEach()
  2. 요소의 소모: reduce()
  3. 요소의 검색: findFirst(), findAny()
  4. 요소의 검사: anyMatch(), allMatch(), noneMatch()
  5. 요소의 통계: count(), min(), max()
  6. 요소의 연산:  sum(), average()
  7. 요소의 수집 : collect()

 

대표적인 최종 연산 메소드

메소드 설명
void forEach(Consumer<?super T> action) 스트림의 각 요소에 대해 해당 요소를 소모하여 명시된 동작을 수행한다
Optional<T> reduce(BinaryOperator<T> accumulator)
T reduce(T identity, BinaryOperator<T> accumulator)
처음 두 요소를 가지고 연산을 수행한 뒤 그 결과와 다음 요소를 가지고 또 다시 연산을 수행한다
이런 식으로 해당 스트림의 모든 요소를 소모하여 연산을 수행하고, 그 결과를 반환한다.
Optional<T>findFirst()
Optional<T>findAny()
해당 스트림에서 첫 번째 요소를 참조하는 Optional 객체를 반환한다. (findAny() 메소드는 병렬 스트림일 때 사용한다.)
boolean anyMatch(Predicate<? super T> predicate) 해당 스트림의 일부 요소가 특정 조건을 만족할 경우에 true를 반환한다.
boolean allMatch(Predicate<? super T> predicate) 해당 스트림의 모든 요소가 특정 조건을 만족할 경우에 true를 반환한다.
boolean noneMatch(Predicate<? super T> predicate) 해당 스트림의 모든 요소가 특정 조건을 만족하지 않을 경우에 true를 반환한다.
long count() 해당 스트림의 요소의 개수를 반환한다.
Optional<T> max(Comparator<? super T>comparator) 해당 스트림의 요소 중에서 가장 큰 값을 가지는 요소를 참조하는 Optional 객체를 반환한다.
Optional<T>min(Comparator<? super T>comparator) 해당 스트림의 요소 중에서 가장 작은 값을 가지는 요소를 참조하는 Optional 객체를 반환한다.
T sum() 해당 스트림의 모든 요소에 대해 합을 구하여 반환한다.
Optional<T> average() 해당 스트림의 모든 요소에 대해 평균값을 구하여 반환한다.
<R,A>R collect(Collector<? super T,A,R> collector) 인수로 전달되는 Collectors객체에 구현된 방법대로 스트림의 요소를 수집한다.

 

출처

 

'Spring' 카테고리의 다른 글

[JPA] OSIV 와 성능 최적화  (0) 2023.06.08
[SpringBoot] @MappedSuperclass  (0) 2023.05.21
[SpringBoot] 싱글톤(Singleton) 이란?  (0) 2023.05.12
[java] Dependency Injection 개념  (0) 2023.05.11
[SpringSecurity] AccessDeniedHandler  (0) 2023.05.09

스프링은 EJB의 무겁고 복잡한 플랫폼에서 벗어나 POJO기반의 경량화된 개발 환경을 제공하는 오픈소스 프레임워크

 

좋은 객체 지향 설계의 5가지 원칙(SOLID)

 

SOLID

-SRP : 단일 책임원칙(Single Responsibility Principle)

한클래스는 하나의 책임만 가져야 한다.

중요한 기준은 변경! 변경이 있을때 파급효과 적으면 단일 책침 원칙을 잘 따른것!

 

-OCP: 개방-폐쇄의 원칙(Open/Closed Principle)

소프트웨어 요소는 확장에는 열려있고 변경에는 닫혀있어야 한다.

다형성 활용!

 

-LSP: 리스코프 치환 원칙(Liskov Substitution Principle)

프로그램의 객체는 프로그램의 정확성을 깨지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다

 

-ISP: 인터페이스 분리 원칙(Interface Segregation Principle)

특정 클라이언트를 위한 여러개의 인터페이스가 범용 인터페이스 하나보다 낫다

인터페이스가 명확해지고, 대체 가능성이 높아진다

 

-DIP: 의존관계 역전 원칙(Dependency Inversion Principle)

구현 클래스에 의존하지 말고, 인터페이스에 의존하라는 뜻

역할에 의존하게 해야한다


싱글톤 패턴이란?

객체의 인스턴스가 오직 1개만 생성되는 패턴을 의미한다.

 

그럼 싱글톤 패턴을 사용하는 이유는 무엇인가?

먼저 메모리 측면에서 이점을 가질 수있다.

최초 한번의 new 연산자를 통해서 고정된 메모리 영역을 사용하며 만약 다른 객체가 해당 객체에 접근 할 때 메모리 낭비를 방지 할 수 있다. 또 한 이미 생성된 인스턴스에 접근하기에 속도측면에서도 이점을 가질 수 있다.

또 클래스 간에 데이터 공유가 쉽다. 싱글톤 인스턴스는 전역에서 사용되는 인스턴스이기에 다른 클래스의 인스턴스들이 접근하여 사용이 가능하다. 하지만 동시에 여러 인스턴스가 접근 시 동시성 문제가 발생하기도 한다.

 

싱글턴패턴은 위처럼 좋은 이점이 많이 있지만 문제점 또 한 가지고 있다.

  1. 싱글톤 패턴을 구현하는 코드 자체가 많이 필요하다. 동시성 문제 해결을 위한 Syncronized 키워드 사용이 필요하다
  2. 테스트가 어렵다. 싱글톤은 자원을 공유하기 때문에 격리된 환경에서 테스트를 수행하려면 매번 인스턴스의 상태 초기화를 해야한다. 그렇지 않으면 전역에서 상태를 공유하기에 테스트가 정확하게 수행이 불가능하다.
  3. 의존 관계상 클라이언트가 구체 클래스에 의존한다. new키워드를 사용하여 클래스 안에서 객체를 생성하므로 이는 SOLID 법칙의 DIP를 위반하며, OCP 원칙 또한 위반할 가능성이 높다.
  4. 자식클래스를 만들 수 없다, 내부 상태 변경이 어렵다 등 여러 문제점 또한 가지고 있다. 

 

결과적으로 싱글톤 패턴은 유연성이 많이 떨어지는 패턴이다. 

하지만 단독사용이 아닌 스프링 컨테이너 같은 프레임워크의 도움을 받으며 싱글톤 패턴의 문제점을 보완하면서 장점을 사용 할 수 있다.

 

 

출처

https://tecoble.techcourse.co.kr/post/2020-11-07-singleton/

 

싱글톤(Singleton) 패턴이란?

이번 글에서는 디자인 패턴의 종류 중 하나인 싱글톤 패턴에 대해 알아보자. 싱글톤 패턴이 무엇인지, 패턴 구현 시 주의할 점은 무엇인지에 대해 알아보는 것만으로도 많은 도움이 될 것이라

tecoble.techcourse.co.kr

 

'Spring' 카테고리의 다른 글

[SpringBoot] @MappedSuperclass  (0) 2023.05.21
[Java] Stream이란?  (0) 2023.05.14
[java] Dependency Injection 개념  (0) 2023.05.11
[SpringSecurity] AccessDeniedHandler  (0) 2023.05.09
[SpringBoot] @Slf4j 와 @Log4j2  (0) 2023.05.08

DI란 무엇인가?

DI(Dependency Injection)은 의존성 관계 주입이라 한다.

 

그러면 Dependency 의존관계는?

 

토비의 스프링에서는 '의존대상 B가 변하면 그것이 A에 영향을 미친다'  즉

B의 기능이 추가 또는 변경되거나 형식이 바뀐다면 그것이 A에 영향을 미친다는 의미인다.

의존관계를 인터페이스로 추상화하면 더 다양한 의존관계를 맺을 수 있으며

실제 구현 클래스와의 관계가 느슨해지고 결합도가 낮아진다

 

 

 

의존성 주입이 필요한 이유

public class Store{
    private Pencil pencil;

    public Store() {
        this.pencil = new Pencil();
    }
    

만약 연필과 연필을 판매하는 store 클래스가 있다 가정하자

위의 코드는 두 가지의 문제점을 가지고 있다.

  1. 두 클래스는 강하게 결합되어 있다.
  2. 객체들 간의 관계가 아닌 클래스 간의 관계가 맺어진다.

 

1. 두 클래스가 강하게 결합되어 있다.

두 클래스는 강하게 결합되어 있어  만약 연필이 아닌 지우개와 같은 다른 상품을 판매한다면 Store클래스의 생성자를 변경하는 작업이 필요하다.

이러한 부분은 코드의 유연성을 떨어트리며 이러한 해결점으로 상속이 있지만 상속은 제약이 많으며 확장성이 떨어지므로 피하는 것이 좋다.

 

2. 객체들 간의 관계가 아니라 클래스 간의 관계가 맺어진다.

Store와 Pencil은 클래스간의 관계가 맺어져 있다는 것이 문제이다.

올바른 객체지향적 설계라면 객체들간의 관계가 맺어져야한다.
객체들 간의 관계가 맺어지게 되면 다른 객체의 구체 클래스를 전혀 알지 못하더라도

(해당 클래스가 인터페이스를 구현하였다면) 인터페이스의 타입으로 사용할 수 있다.

 

위의 두 문제점이 발생하는 이유는 Store에서 어떤 제품을 판매할지에 대한 관심이 분리되지않았기 때문이다.

이러한 문제점을 해결하기 위해 Spring에서는 DI(Dependency Injection)을 사용하였다.

 

 

 

의존성 주입을 통해 해결

위의 문제를 해결 하기 위해 다형성이 필요하다. 모든 제품을 하나로 표현하기 위한 Product라는 인터페이스를 도입한다.

public interface product {
    
}

public class Pencil implements product {
    
}

 

 

그후 강하게 결합되어 있는 부분을 제거한다.

제거하기 위한 방법은 외부에서 상품을 주입(Injection)받아야한다.

public class Store {
    private Product product;

    public Store(Product product) {
        this.product = product;
    }
}

이러한 이유로 Spring이라는 Di컨테이너가 필요하다

Store에서 Product 객체를 주입하기 위해 애플리케이션 실행 시점에 필요한 객체(빈)을 생성하며, 

의존성이 있는 두 객체를 연결하기 위한 한 객체를 다른 객체로 주입 시켜야한다.

 

이러한 부분은 스프링 프레임워크가 완벽하게 지원해준다.

스프링은 특정 위치부터 클래스 탐색, 객체생성, 객체관계설정까지 하며 이러한 특징으로 스프링은 DI 컨테이너라고도 한다.

이러한 개념은 제어의역전(Inversion Of Control, IOC)  라고 하기도 한다.

 

 

 

 

의존성 주입 정리

 

Spring은 의존성 주입을 도와주는  DI 컨테이너로써, 강하게 결합된 클래스들을 분리하고

애플리케이션 실행 시점에 객체간의 관계를 결졍함으로써 결합도를 낮추고 유연성을 확보한다.

한 객체가 다른 객체를 주입 받으려면 반드시 DI컨테이너에 의해 관리 되어야 한다.

  • 두 객체간의 관계라는 관심사의 분리
  • 두 객체간의 결합도를 낮춤
  • 객체의 유연성을 높임
  • 테스트 작성을 용이하게 한다.

의존관계 주입할 객체를 계속해서 생성 및 소멸한다면 성능에 부담이 될 수 밖에없어 

스프링은 기본적으로 싱글톤(Singleton)으로 관리한다.

 

 

 

 

출처:

https://mangkyu.tistory.com/150

 

[Spring] 의존성 주입(Dependency Injection, DI)이란? 및 Spring이 의존성 주입을 지원하는 이유

1. 의존성 주입(Dependency Injection)의 개념과 필요성 [ 의존성 주입(Dependency Injection) 이란? ] Spring 프레임워크는 3가지 핵심 프로그래밍 모델을 지원하고 있는데, 그 중 하나가 의존성 주입(Dependency Inj

mangkyu.tistory.com

 

'Spring' 카테고리의 다른 글

[Java] Stream이란?  (0) 2023.05.14
[SpringBoot] 싱글톤(Singleton) 이란?  (0) 2023.05.12
[SpringSecurity] AccessDeniedHandler  (0) 2023.05.09
[SpringBoot] @Slf4j 와 @Log4j2  (0) 2023.05.08
[SpringBoot] @Transactional에 대해  (0) 2023.05.07

1. AccessDeninedHandler이란?

 

Spring Security에서 제공하는 인터페이스로, 사용자가 자신이 권한이 없는 리소스에 접근하려고 할 때 이를 처리하는 역할을 담당한다.

이 인터페이스를 구현하여 사용자 정의 AccessDeniedHandler를 작성하면, 권한이 없는 사용자가 리소스에 접근하려고 할 때 어떻게 처리할지를 정의한다. 예를 들어, 사용자를 특정 오류 페이지로 리디렉션하거나, HTTP 상태 코드를 반환하거나, 사용자에게 메시지를 표시하는 등의 동작을 정의할 수 있다.

 

예를 들어 내가 현재 진행중인 프로젝트에서 예를 들것이다.

 

SecurityConfig

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

    //인증 설정
    http.authorizeRequests()
            .antMatchers("/admin/**").hasRole("ADMIN")
            .anyRequest().permitAll()
            .and()
            .formLogin()
            .loginPage("/member/login")
            .defaultSuccessUrl("/")
            .permitAll()
            .and()
            .logout()
            .logoutRequestMatcher(new AntPathRequestMatcher("/member/logout"))
            .logoutSuccessUrl("/")
            .invalidateHttpSession(true)
            .and()
            .exceptionHandling().accessDeniedHandler(new CustomAccessDeniedHandler());
    return http.build();
}

에서

.antMatchers("/admin/**").hasRole("ADMIN")

코드를 통해 /admin의 하위 링크는 ADMIN이란 권한을 가지고 있는 사람만 접근을 가능하게 하였다.

이때 만약 권한이 없는 사용자가 접근하면 어떻게 되는가?

마지막의

.exceptionHandling().accessDeniedHandler(new CustomAccessDeniedHandler());

코드에서 처리하게된다.

이때 .exceptionHandling()은 Spring Security 설정에서 예외 처리 설정을 제공하며 이 메서드를 이용해 인증 오류 또는 권한이 없는 접근과 같은 보안 관련 예외가 발생 하였을 때 어떤 동작을 수행하는지 정의할 수 있다.

이때 나는 accessDeniedHandler(new CustomAccessDeniedHandler());를 통해 보안 관련 예외 발생시 동작 수행을 직접 설정해 주었다.

 

 

CustomAccessDeniedHandler

public class CustomAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        response.sendRedirect("/accessBlock");
    }
}

AccessDeniedHandler의 인터페이스를 구현하며 '/accessBlock' 경로로 이동하도록 설정하였다.

이처럼 보안 관련 예외 발생 시 처리를 돕기 위한 인터페이스이다.

스프링은 EJB의 무겁고 복잡한 플랫폼에서 벗어나 POJO기반의 경량화된 개발 환경을 제공하는 오픈소스 프레임워크

 

좋은 객체 지향 설계의 5가지 원칙(SOLID)

 

SOLID

-SRP : 단일 책임원칙(Single Responsibility Principle)

한클래스는 하나의 책임만 가져야 한다.

중요한 기준은 변경! 변경이 있을때 파급효과 적으면 단일 책침 원칙을 잘 따른것!

 

-OCP: 개방-폐쇄의 원칙(Open/Closed Principle)

소프트웨어 요소는 확장에는 열려있고 변경에는 닫혀있어야 한다.

다형성 활용!

 

-LSP: 리스코프 치환 원칙(Liskov Substitution Principle)

프로그램의 객체는 프로그램의 정확성을 깨지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다

 

-ISP: 인터페이스 분리 원칙(Interface Segregation Principle)

특정 클라이언트를 위한 여러개의 인터페이스가 범용 인터페이스 하나보다 낫다

인터페이스가 명확해지고, 대체 가능성이 높아진다

 

-DIP: 의존관계 역전 원칙(Dependency Inversion Principle)

구현 클래스에 의존하지 말고, 인터페이스에 의존하라는 뜻

역할에 의존하게 해야한다


@Slf4j에 대한 글을 적으려다 비슷한 @Log4j2에 대해서 찾아보게되었다.

@Slf4j는 사용해 보았지만 @Log4j2는 사용해 보질 않아 두가지 모두 정리해보고 싶어 작성하였다.

 

 

1.@Slf4j

 

필자가 사용해본 로깅 라이브러리이며 여러 로깅 프레임워크와의 호환성을 제공하는 추상화 레이어이며 이 추상화 레이어의 interface모음이다. 장점은 다양한 로깅 구현체를 쉽게 교체할 수 있다는 것이다.

 

사용법은

@Slf4j
public class StudyController {
}

와 같이 상단에 선언을 해주면 되고

log.trace("가장 디테일한 로그");
log.warn("경고");
log.info("정보성 로그");
log.debug("디버깅용 로그");
log.error("에러");

각 코드를 상황에 맞게 사용하면 된다

 

로깅 레벨은 (많은 로깅)trace > warn > info > debug > error(적은로깅) 순이다

 

 

2. Log4j2

 

필자가 사용해 보지 못한 로깅 라이브러리이며 개발자가 로깅 메시지를 캡처하고, 필요에 따라 다양한 방법으로 출력하도록 도와준다.

 

사용법은

logger.log(Level.ALL,"LOG TEST");
        logger.trace("TRACE TEST");
        logger.info("INFO TEST");
        logger.debug("DEBUG TEST");
        logger.warn("WARN TEST");
        logger.error("ERROR TEST");
        logger.fatal("FATAL TEST");

 

 

3. 무엇을 더 많이 사용하는가?

 

두 라이브러리 모두 장단점이 있으며 프로젝트의 요구 사항과 개발자의 선호에 따라 선택할 수 있다.

SLF4J를 사용하면 다양한 로깅 구현체를 쉽게 교체할 수 있으므로, 더 넓은 범위의 프로젝트에 적합할 수 있다. 

Log4j2는 향상된 성능과 기능을 제공하므로, 이러한 특성을 활용하려는 프로젝트에서 더 적합할 수 있다.

스프링은 EJB의 무겁고 복잡한 플랫폼에서 벗어나 POJO기반의 경량화된 개발 환경을 제공하는 오픈소스 프레임워크

 

좋은 객체 지향 설계의 5가지 원칙(SOLID)

 

SOLID

-SRP : 단일 책임원칙(Single Responsibility Principle)

한클래스는 하나의 책임만 가져야 한다.

중요한 기준은 변경! 변경이 있을때 파급효과 적으면 단일 책침 원칙을 잘 따른것!

 

-OCP: 개방-폐쇄의 원칙(Open/Closed Principle)

소프트웨어 요소는 확장에는 열려있고 변경에는 닫혀있어야 한다.

다형성 활용!

 

-LSP: 리스코프 치환 원칙(Liskov Substitution Principle)

프로그램의 객체는 프로그램의 정확성을 깨지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다

 

-ISP: 인터페이스 분리 원칙(Interface Segregation Principle)

특정 클라이언트를 위한 여러개의 인터페이스가 범용 인터페이스 하나보다 낫다

인터페이스가 명확해지고, 대체 가능성이 높아진다

 

-DIP: 의존관계 역전 원칙(Dependency Inversion Principle)

구현 클래스에 의존하지 말고, 인터페이스에 의존하라는 뜻

역할에 의존하게 해야한다


 

 

프로젝트 진행중 @Transactional에 대한 궁금증이 생겨 이에 대해 찾아보았습니다..

 

 

1. Transaction이란?

데이터베이스의 상태를 변경하고자 할 때, 한번에 수행되어야 하는 연산들을 의미합니다.

 

트랜잭션은 4가지 성질을 가지고 있습니다(트랜잭션 ACID성질)

 

  1. 원자성(Atomicity): 트랜잭션은 원자성을 가져야 합니다. 한 트랜잭션 내에서 실행한 작업들은 하나의 단위로 처리하며 모두 성공하거나 모두 실패해야합니다. 이에 rollback이 필수입니다.
  2. 일관성(Consistency): 트랜잭션은 일관성 있는 데이터베이스 상태를 유지해야 합니다. 연산이 실행될 수 있는 환경들이 조건으로 주어지고, 이에 반드시 만족해야합니다.
  3. 격리성(Isolation): 동시에 실행되는 트랜잭션들이 서로 영향을 미치지 않아야 합니다.
  4. 영속성(Durability): 성공적으로 완료(Commit)된 트랜잭션은 데이터베이스에 영구적으로 보존되어야 합니다. 완료 후 프로그램이 종료된다면 데이터는 이미 저장되어 보존되며, 완료 전 프로그램이 종료된다면 데이터는 원자성 원칙에 따라 트랜잭션 수행 전으로 돌아가야합니다.

 

이에 만약 첫 번째 실행 후 두번째 연산을 할 때 만약 예외가 발생한다면 첫 번째 연산도 취소해주어야 합니다.

이때 @Transactional을 사용하게 되면 이에 첫 번째 연산까지 취소해주는 롤백(rollback)처리를 합니다.

 

 

 

2. @Transactional이란?

 

@Transactional은 트랜잭션을 선언하고 begin, commit까지 자동으로 수행합니다. 

예외가 발생 할 시 rollback처리도 자동으로 수행해줍니다.

그리고 이것이 적용된 범위에서는 트랜잭션 기능이 포함된 프록시 객체가 생성되어 자동으로 commit 또는

rollback을 진행합니다.

 

 

 

 

3.@Transactional(readOnly = true)는 필요한가?

 

사용하는 것이 좋습니다.

 

먼저 조회한 데이터를 return한다 하여도 의도치 않게 데이터가 변경되는 일을 사전에 방지합니다.

해당 옵션인 경우 CUD가 동작하지 않고, 스냅샷 저장, 변경감지(dirty check)의 작업을 수행하지 않아 성능이 향상됩니다.

  • dirtycheck는 상태변경 검사인데 JPA에서 트랜잭션이 끝나는 시점에 변화가 있는 모든 엔티티 객체를 데이터베이스에 자동으로 반영합니다.

그다음은 DB서버의 부하를 줄이고 약간 최적화가 가능하며 @Transactional(readOnly = true) 어노테이션을 보게된다면 코드를 보는 사람들은 직관적으로 이 메서드가 read에 대해서만 작업을 한다는 것을 예상할 수 있습니다.

 

1.@RequestParam

 

1.@RequestParam이란?

URL에서 파라미터 값과 이름을 함께 전달하는 방식이며 게시판등에서 페이지 및 검색 정보를 함께 전달하는 방식을 사용할 때 많이 사용한다.

 

2.@RequestParam의 4가지 파라미터

  1. defaultValue: 값이 없을 떄 기본적으로 전달할 값
  2. name: uri에서 바인딩할 파라미터의 이름
  3. value: uri에서 바인딩하여 별칭으로 정할 값
  4. required: 필수적으로 전달되어야 하는 파라미터인지 설정한다.

3.예시

@RequestParam(value ="id", name = "id", required = false, defaultValue = "1" )

 

 

2.@PathVariable

 

1.@pathvariable이란?

어떤 요청이든지 보낼 수 있는 값은 1개밖에 없으며 주로  RestAPI에서 많이 사용되고 좀 더 직관적이다.

 

2.예시

@PathVariable("memNum") int memNum

 

 

3.차이점

@PathVariable은 @RequestParam과 다르게 하나만 받아 올 수 있으므로 여러개의 데이터를 받아올때는 @RequestParam을 사용해야한다.

@PathVariable은 @RequestParam과 다르게 default값을 설정하지 않으므로 default값이 필요한 조회 요청을 하게 될 경우 @RequestParam을 사용하면된다.

 

 

또 한 두가지를 모두 사용하는것도 가능하다.

CustomUserDetails는 스프링 시큐리티 프레임워크에서 제공하는 인터페이스이다.

public interface UserDetails extends Serializable {


    Collection<? extends GrantedAuthority> getAuthorities();


    String getPassword();


    String getUsername();


    boolean isAccountNonExpired();


    boolean isAccountNonLocked();


    boolean isCredentialsNonExpired();


    boolean isEnabled();

}

1.Collection<? extends GrantedAuthority> getAuthorities();

인증된 사용자 권한 정보를 반환하는 메서드입니다.

반환된 객체는 GrantedAuthority 인터페이스를 구현한 객체들의 컬렉션이며

각 객체는 사용자가 가지고 있는 권한을 나타낸다.

 

2.String getPassword();

인증된 사용자의 비밀번호를 반환하는 메서드이다.

 

3.String getUsername();

인증된 사용자의 아이디(이름)을 반환하는 메서드이다.

 

4.boolean isAccountNonExpired();

인증된 사용자의 계정이 만료되었는지 여부를 반환하는 메서드입니다.

계정이 만료되었다면 false를 반환합니다.

 

5.boolean isAccountNonLocked();

인증된 사용자의 계정이 잠겨있는지 여부를 반환하는 메서드입니다.

계정이 잠겨있다면 false를 반환합니다.

 

6.boolean isCredentialsNonExpired();

인증된 사용자의 비밀번호가 만료되었는지 여부를 반환하는 메서드입니다.

비밀번호가 만료되었다면 false를 반환합니다.

 

7. boolean isEnabled();

인증된 사용자의 계정이 활성화되어 있는지 여부를 반환하는 메서드입니다.

계정이 활성화되어 있다면 true를 반환합니다.

 

+ Recent posts