ORM, JPA, Spring Data JPA 

  • ORM : 객체(Object)와 관계형 데이터(Relational data) 를 매핑하기 위한 기술이다. 객체와 테이블 관계를 바탕으로 SQL문장을 자동으로 생성하여 객체로 DB를 조작하게 하는 기술.
  • JPA : 자바 ORM 기술에 대한 API 표준 명세이다. ORM을 사용하는 방식을 정의한 인터페이스를 모아둔 것. JPA는 특정 기능을 하는 라이브러리가 아니며, 말그대로 인터페이스이다. 따라서 사용방식에 대해서만 정의했을 뿐 구현이 없다.
  • Hibernate : JPA라는 명세의 구현체. 즉, JPA 인터페이스를 구현한 라이브러리 중 하나로 현 프레임워크 중 가장 주도 하고 있다.
  • Spring Data JPA : Spring Data JPA는 JPA를 쓰기 편하게 만들어놓은 모듈이다. JPA를 한 단계 추상화시킨 Repository라는 인터페이스를 제공함으로써 JPA를 사용할 때 예상가능하고 반복적인 코드들을 대신 작성해주어 코드를 줄일 수 있도록 해준다.  

 

 ORM

  ORM 이란 Object-Relational Mapping 의 약자로, 이름 그대로 객체(Object)와 관계형 데이터(Relational data) 를 매핑하기 위한 기술이다. 즉, 내가 코드 상에서 생성한 객체가 DB상에 어떤 테이블과 연결이 된다는 것을 의미한다. 이러한 매핑이 필요한 이유는 객체 지향 언어과 관계형 데이터베이스사이의 패러다임 불일치가 있기때문이다.  이 둘 간의 패러다임 불일치 때문에 개발자는 더 많은 코드를 작성해야 하며, 이는 반복적이고 실수하기 쉬운 작업이 된다. 그렇기 때문에 개발자는 객체지향적인 설계에 집중할 수 없게 된다. ORM이 바로 이러한 문제를 해결해 준다. 

 

https://medium.com/@emccul13/object-relational-mapping-9d84807f5536

 

 패러다임 불일치

객체 지향 프로그래밍과 관계형 데이터베이스 사이의 데이터 표현 방식이 달라서 생기는 문제를 패러다임 불일치라고 한다. 패러다임 불일치가 일어나는 이유는 애초에 이들의 목표와 동작 방식이 다르기 때문이다.

  • 객체 지향
    • 필드와 메서드 등을 묶어서 객체로 잘 만들어 사용하는 것이 목표
    • 객체 지향 프로그래밍은 추상화, 캡슐화, 정보은닉, 상속, 다형성 등 시스템의 복잡성을 제어할 수 있는 다양한 장치들을 제공한다.
  • 관계형 데이터베이스
    • 데이터를 잘 정규화해서 보관하는 것이 목표

 

 

JPA

  JPA는 Java Persistence API의 약자로, 자바 ORM 기술에 대한 API 표준 명세이다. 즉, 인터페이스의 모음이다. 이러한 JPA 인터페이스를 구현한 대표적인 프레임워크가 하이버네이트(Hibernate)이다.JPA는 애플리케이션과 JDBC 사이에서 동작한다. 개발자가 JPA를 사용하면, JPA 내부에서 JDBC API를 사용하여 SQL을 호출하여 DB와 통신한다. 즉, 개발자가 직접 JDBC API를 쓸 필요가 없다.

 

 

 Hibernate

    JPA를 구현한 프레임워크 중 사실상 표준이다. 오픈소스 소프트웨어이다. 여기서 주목해야할 점은 JPA 기술 스펙이고 하이버네이트는  기능을 구현하여 공급해주는 역할이다.

 

Spring Data JPA

 Spring framework에서 JPA를 편리하게 사용할 수 있도록 지원하는 프로젝트(모듈)이다. Spring Data JPA의 목적은 JPA를 사용할 때 필수적으로 생성해야하나, 예상가능하고 반복적인 코드들을 대신 작성해줘서 코드를 줄여주는 것이다. 이는 JPA를 한 단계 추상화시킨 Repository라는 인터페이스를 제공함으로써 이루어진다.

 Spring Data JPA는 JPA Provider이 아니다. 단지 데이터 계층에 접근하기 위해 필요한 뻔한 코드들의 사용을 줄여주도록 하는 인터페이스이다. 여기서 반드시 기억해야할 점은 Spring Data JPA 항상 하이버네이트와 같은 JPA provider 필요하다는 것이다.

 

 

출처 : 스프링부트와 aws로 혼자 구현하는 웹서비스(이동욱 저)

 

 

 

 

 

참고 자료 : https://doing7.tistory.com/105

스프링에서 DI (의존성 주입) 를 사용하는 이유

 

① DI(의존성 주입)이란?

  • DI란 외부에서 두 객체 간의 관계를 결정해주는 디자인 패턴으로, 인터페이스를 사이에 둬서 클래스 레벨에서는 의존관계가 고정되지 않도록 하고 런타임 시에 관계를 다이나믹하게 주입하여 유연성을 확보하고 결합도를 낮출 수 있게 해준다.
  • 즉, 객체간의 의존성을 스프링 컨테이너(Spring Container)가 자동으로 연결해주는 것으로, 개발자가 빈(Bean) 설정파일에 의존관계가 필요한 정보를 추가해주면, 스프링 컨테이너가 자동적으로 연결해 준다
  • 의존성이란 한 객체가 다른 객체를 사용할 때 의존성이 있다고 한다.
  • 의존성 주입은 IoC(Inversion of Control: 제어의 역전)원칙 하에 객체 간의 결합을 약하게 해주고 유지보수가 좋은 코드를 만들어 준다. 또한 의존성 주입은 개발자들이 객체를 생성하는 번거로움과 다양한 케이스를 고려하는 겨우를 줄이고, 변수 사용과 개발에 더욱이 집중할 수있게 해준다.

* IoC 란?

  • IoC(Inversion of Control)란 "제어의 역전" 이라는 의미로, 말 그대로 메소드나 객체의 호출작업을 개발자가 결정하는 것이 아니라, 외부에서 결정되는 것을 의미한다.
  • 객체의 의존성을 역전시켜 객체 간의 결합도를 줄이고 유연한 코드를 작성할 수 있게 하여 가독성 및 코드 중복, 유지 보수를 편하게 할 수 있게 한다.
  • 스프링이 모든 의존성 객체를 스프링이 실행될때 다 만들어주고 필요한곳에 주입시켜줌으로써 Bean들은 싱글턴 패턴의 특징을 가지며, 제어의 흐름을 사용자가 컨트롤 하는 것이 아니라 스프링에게 맡겨 작업을 처리하게 된다.

흐름의 변화 상세 설명 

더보기

기존의 순서는 아래와 같았다.

1. 객체 생성
2. 의존성 객체 생성 (클래스 내부에서 생성)
3. 의존성 객체 메소드 호출

하지만, 스프링에서는 다음과 같은 순서로 객체가 만들어지고 실행된다.

1.객체 생성
2. 의존성 객체 주입 (스스로가 만드는것이 아니라 제어권을 스프링에게 위임하여 스프링이 만들어놓은 객체를 주입한다.)
3. 의존성 객체 메소드 호출

 

 

② DI(의존성 주입)를 사용하는 이유?

  1. 재사용성을 높여준다.
  2. 테스트에 용이하다.
  3. 코드를 단순화 시켜준다.
  4. 사용하는 이유를 파악하기 수월하고 코드가 읽기 쉬워지는 점이 있다.
  5. 종속성이 감소하기 때문에 변경에 민감하지 않다.
  6. 결합도(coupling)는 낮추면서 유연성과 확장성은 향상 시킬 수 있다.
  7. 객체간의 의존관계를 설정할 수 있다.

 

③ 스프링에서 의존성을 주입하는 방법

  • 생성자에서 주입
  • 필드에서 주입
  • setter 에서 주입

 

참고 자료 https://velog.io/@gillog/Spring-DIDependency-Injection

스프링 프레임워크

 

①  스프링 프레임워크(Spring Framework)

  • 여러 프레임워크들 중 자바(JAVA)를 기반으로 하는 프레임워크 이다.
  • 대한민국 공공기관의 웹 서비스 개발 시 사용을 권장하고 있는 전자정부 표준프레임워크 이다.
  • 스프링의 다른 프레임워크와 가장 큰 차이점은 다른 프레임워크들의 포용이다. 이는 다시말해 기본 뼈대를 흔들지 않고, 여러 종류의 프레임워크를 혼용해서 사용할 수 있다는 점.

 

② 스프링 프레임워크 특징

  •  POJO(Plan Old Java Object)기반의 구성
    - 코드를 개발할 때 개발자가 특정한 라이버리나 컨테이너의 기술에 종속적이지 않다는 것을 의미
    - 쉽게말해 Java코드를 이용해서 객체를 구성하는 방식을 그대로 스프링에서 사용할 수 있다는 의미

 

  • 의존성 주입
    -  의존성 주입은 하나의 객체가 다른객체의 의존성을 제공하는 테크닉
    - "어떤 객체가 필요한 객체를 외부에서 밀어 넣는다."는 의미
    - "의존성 주입"을 사용하여 갖는 장점은 '주입을 받는 입장에서는 어떤 객체인지 신경 쓸 필요가 없다.', '어떤 객체에 의존하든 자신의 역할은 변하지 않는다.'이다.
    - "ApplicationContext"라는 존재가 필요한 객체들을 생성하고, 필요한 객체들을 주입하는 역할을 해주는 구조
    - "ApplicationContext가 관리하는 객체들을 "빈(Bean)"이라고 한다.
    - 빈과 빈 사이의 의존 관계를 'xml 설정', '어노테이션 설정', 'Java 설정 방식'을 통해서 처리 할 수 있다.

 

  • 관점지향프로그래밍(AOP)의 지원
    - 대부분의 시스템에서 '보안'이나 '로그', '트랜잭션'과 같이 무엇을 실행을 하든 반드시 처리가 필요한 부분이 있다. 이를 '횡단 관심사(cross-concern)'라고 한다. 
    - AOP는 이러한 횡단 관심사를 모듈로 분리하는 프로그래밍 패러다임이다.
    - 이 패러다임을 통해서 반복적인 코드를 줄이고, 핵심 비즈니스 로직에만 집중을 할 수 있다.

 

  • 높은 확장성
    - 스프링 프레임워크에 통합하기 위해 간단하게 기존 라이브러리를 감싸는 정도로 스프링에서 사용이 가능하다.
    - 따라서 수많은 라이브러리가 이미 스프링에서 지원되고 있고 스프링에서 사용되는 라이브러리를 별도로 분리하기도용이하다.

 

③ 스프링 프레임워크 사용이유(장점)

  • 정형화 되어 있기 때문에 일정수준의 품질을 기대 할 수 있다.
  • 개발 후 유지보수 및 기능의 확장성에서도 품질을 보장한다.
  • '전자표준 프레임워크'기 때문에 해당 프레임워크의 수요가 크다.(한국 한정)

 

④ 스프링 프레임워크 단점

  • 내부에서 많은 기능을 가졌기 때문에 상당히 무겁다.
  • 분명 많은 기능을 제공해서 편리하지만, 이 기능들을 습득하기위해 상당한 노력과 시간이 필요하다.

 

 

참고자료 : 

https://kimvampa.tistory.com/35

 

생성자 자동완성 어노테이션

@AllArgsConstructor

모든 변수를 사용하는 생성자를 자동완성 시켜주는 어노테이션

@AllArgsConstructor
public class Order {
    private String food;
    private int price;
    private String makers;

    /*@AllArgsConstructor를 사용하면 아래와 같은 생성자를 자동 생성할 수 있다.
    public Order(String food, int price, String makers) {
        this.food = food;
        this.price = price;
        this.makers = makers;
    }
    */
    }

 

@NoArgsConstructor

어떠한 변수도 사용하지 않는 기본 생성자를 자동완성 어노테이션이다.

@NoArgsConstructor
public class Order {
    private String food;
    private int price;
    private String makers;

    /*@NoArgsConstructor 사용하면 아래와 같은 생성자를 자동 생성할 수 있다.
    public Order() {

    }
    */
}

 

@RequireArgsConstructor

특정 변수만을 활용하는 생성자를 자동완성 시켜주는 어노테이션이다. 생성자의 인자로 추가할 변수에 @NonNull 어노테이션을 붙여서 해당 변수를 생성자의 인자로 추가할 수 있다. 아니면 해당 변수를 final로 선언해도 의존성을 주입받을 수 있다.

@RequireArgsConstructor
public class Order {
    @NotNull
    private String food;
    private final int price;
    private String makers;

    /*@RequireArgsConstructor 사용하면 아래와 같은 생성자를 자동 생성할 수 있다.
    public Order(String food, int price) {
        this.food = food;
        this.price = price;
    }
    */
}

@Builder(번외)
Builder 패턴이란 점증적 생성자 패턴과 자바빈즈 패턴의 단점을 보완하기 위해 사용되는 디자인패턴이다. @Builder 어노테이션을 사용하면 클래스 객체 생성시 Builder 패턴을 적용시켜준다. 모든 변수들에 대해 build하기를 원한다면 클래스 위에 @Builder를 붙이면 되지만, 특정 변수만을 build하기 원한다면 생성자를 작성하고 그 위에 @Builder 어노테이션을 붙여주면 된다.

Builder 패턴을 적용시 장점

  • 불필요한 생성자의 제거
  • 데이터의 순서에 상관없이 객체생성 가능
  • 명시적 선언으로 이해하기가 쉬우며 각 인자가 어떤 의미인지 알기 쉽다.
  • setter메서드가 없으므로 변경 불가능한 객체를 만들수있다.
  • 정보들을 다 받은 후에 한번에 객체를 생성하므로 객체일관성이 깨지지 않는다.
  • build()함수가 null인지 체크해주므로 검증이 가능한다.

 

의존성 주입 방법

생성자 주입(Constructor Injection): 생성자를 통해 의존 관계를 주입하는 방법

@Service
public class UserService {

    private UserRepository userRepository;
    private PasswordEncoder passwordEncoder;

    @Autowired
    public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
    }    
}

생성자가 의존성 주입되는 클래스 내에 1개만 존재할 경우 @Autowired 어노테이션을 생략할 수 있다.
생성자 주입을 이용하면 필드 객체에 final(더이상 수정 불가능) 키워드를 사용할 수 있으며, 컴파일 시점에 누락된 의존성을 확인할 수 있다.

@Service
@RequireArgsConstuctor
public class UserService {
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;

}

주입 시킬 객체(UserRepository, PasswordEncoder)에 final 키워드를 붙임으로써 UserService가 스프링 컨테이너에 Bean으로 등록될 때 UserRespository와 PasswordEncoder를 주입시켜준다.

 

수정자 주입(Setter Injection): Setter를 통해 의존 관계를 주입하는 방법

@Service
public class UserService {

    private UserRepository userRepository;
    private PasswordEncoder passwordEncoder;

    @Autowired
    public setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }  

    @Autowired
    public serPasswordEncoder(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }   
}

주입받는 객체가 변경될 가능성이 있는 경우에 사용한다.

 

필드 주입(Field Injection): 필드에 바로 의존 관계를 주입하는 방법

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;
}

필드 주입은 외부에서 접근이 불가능하다는 단점이 존재한다. 또한, 필드 주입은 DI 프레임워크가 존재해야 하므로 프레임 워크와의 의존성이 강하게 결합된다. 따라서 애플리케이션의 구동에 무관한 테스트 코드를 작성하거나 불가피하게 설정해야할 경우를 제외하고 사용을 지양해야한다.

실제 개발 상황에서는 의존 관계의 변경이 필요한 경우는 드물다. 수정자 주입과 같이 수정의 가능성을 열어둔 상태로 개발을 진행하게 되면 유지 보수성이 떨어진다. 그러므로 의존 관계 주입시, 생성자 주입을 통해 변경의 여지를 두지 않고 불변성을 보장하는 것이 좋다.

 

생성자 주입을 사용할 경우의 장점

① 순환 참조 방지

-> 애플리케이션 구동시 객체의 생성 시점에서 에러(컴파일 에러)가 발생하므로 순환 참조 문제를 방지할 수 있다.

② 테스트 코드 작성 용이

-> 생성자 주입을 사용하면 컴파일 시점에 객체를 주입받아 테스트 코드를 작성할 수 있으며, 주입하는 객체가 누락된 경우 컴파일 시점에 오류를 발견할 수 있다

③ 객체의 불변성을 확보할 수 있으며, 객체의 변이를 방지한다.

-> 애플리케이션이 구동되어 @Component 어노테이션을 통해 Spring Bean으로 등록된 final 키워드를 가진 객체들은 객체 생성 이후 내부 상태가 변화하지 않는다.(read-only 메소드만 제공)

참고자료
참고자료2

 


참고자료: https://esoongan.tistory.com/82

 

[JAVA] 빌더패턴 (Builder Pattern) , @Builder

entity나 Dto객체에 값을 넣어줄때 롬복의 빌더 애노테이션(@Builder)을 종종 사용하곤 하는데 완벽히 이해를 하지 못한것같아 정리해보았다! 빌더패턴이란? 디자인패턴중 하나로, 생성과 표현의 분

esoongan.tistory.com

 

 

JWT 사용 흐름

1. Client 가 username, password 로 로그인 성공 시

  • "로그인 정보" → JWT 로 암호화 (Secret Key 사용)
  • JWT 를 Client 응답에 전달. (JWT 전달방법은 개발자가 정함 - 예) 응답 Header 에 아래 형태로 JWT 전달)
  • Client 에서 JWT 저장 (쿠키, Local storage 등)

2. Client 에서 JWT 통해 인증방법

  1. JWT 를 API 요청 시마다 Header 에 포함 - 예) HTTP Headers
  2. Server
    1. Client 가 전달한 JWT 위조 여부 검증 (Secret Key 사용)
    2. JWT 유효기간이 지나지 않았는지 검증
    3. 검증 성공시, JWT → 에서 사용자 정보를 가져와 확인  ex) GET /api/products : JWT 보낸 사용자의 관심상품 목록 조회

 

JWT 구조

  • JWT 는 누구나 평문으로 복호화 가능
  • 하지만 Secret Key 가 없으면 JWT 수정 불가능 → 결국 JWT 는 Read only 데이터

+ Recent posts