Rad Blog

Archive

2022.03.19~2022.03.31 Spring 공부 정리

2022-04-02 Java Spring xfrnk2

개요

  • 넷플릭스 팀 프로젝트 서버 개발 기간동안(2022.03.19~2022.03.31) 지금까지 스프링을 공부하며 남겼던 기록들을 정리해 보았다.
  • 필자는 자바 사용을 시작한지 얼마 되지 않은 초심자고, 스프링은 이번 라이징 캠프 수업을 들으며 처음 접한 프레임워크다.
  • 아직 미흡한 부분이 절대적으로 크다고 느끼고, 이제 막 개념을 배워가고 있는 수준이다.
  • 이후에 조금 더 깊이 있는 영역까지 코드를 뜯어보고 분석해 볼 수 있도록 공부해 가고 싶다.

Spring-boot API 구현하기 위한 선수지식

  • 어노테이션을 다양하게 알아둘 필요가 있다.
  • 롬북을 쓰자.

Spring에 대해 알아보자

1. POJO기반의 구성 (Plain Old Java Object)

코드를 개발할 때, 개발자가 특정한 라이브러리나 컨테이너의 기술에 종속적이지 않음을 의미한다. Java코드를 이용해서 객체를 구성하는 방식 그대로 스프링에서 사용할 수 있다.

덕분에, 자유롭게 객체지향적 설계를 구현할 수 있다. 무슨 말이냐 하면, 개발자는 가장 일반적인 형태로 코드를 작성하고 실행할 수 있다. 때문에 높은 생산성과 유연한 테스트를 할 수 있다는 장점을 가지게 된다.

2. DI(Dependency Injection, 의존성 주입)을 통한 객체 관계 구성

“DI는 객체지향 프로그래밍의 강력한 지원군이다.”

의존성 주입은 제어의 역전이 일어나는것을 전제로 스프링 내부의 객체들 간의 관계를 관리할 때 사용한다. 의존성 주입은 특정 개체에 필요한 객체를 외부에서 결정하여 연결시키는 것을 말한다. 자바에서는 인터페이스를 사용하려 의존적인 관계를 처리한다.

  • 메소드나 객체(bean)의 호출 작업은 제어의 역전을 통해 외부에서 이루어진다. (여기서 외부라 함은 객체를 기준으로 봤을 때의 외부를 의미한다.)
  • 제어의 역행을 전제조건으로 의존성 주입이 일어난다.
  • 의존성을 가진 객체에 대해 스프링에서 의존성 주입이 발생하도록 한다.
  • 의존성 주입 특싱으로 인해 개발자가 POJO 개발이 가능하게 된다.

실무에서는 주로 정형화된 컨트롤러, 서비스, 리포지토리 같은 코드는 컨포넌트 스캔을 사용한다. 그리고 정형화 되지 않거나, 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다.

컴포넌트 스캔과 자동 의존관계 설정

예를 들어, MemberController의 생성자에 @Autowired를 붙임으로써, 스프링은 스프링이 저장하고 있는 memberSevice 객체를 컨트롤러가 생성될 때 가져와 준다. 즉, 생성자에 @Autowired가 있으면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어준다. 이렇게 객체 의존관계를 외부에서 넣어주는 것을 의존성 주입(DI)라 한다.

스프링이 시작될 때, @Controller, @Service, @Repository와 같은 컴포넌트들을 스캔하고 스프링에 빈으로 등록한다. 기본적으로 @Component가 있으면 스프링 빈으로 자동등록 되며, 위의 세 어노테이션도 @Component를 포함하고 있기에 스프링 빈으로 자동 등록 된다. 스프링 빈으로 등록된다면, “스프링 컨테이너에서 빈이 관리된다"라고 말한다. 이후 @Autowired 어노테이션으로 등록된 빈들의 의존 관계를 연결한다.

https://blog.kakaocdn.net/dn/bLOQ6r/btq0XO6pon2/yOWgFMYrmzQkCfUAOuQPQ0/img.png

예를 들어, MemberController의 생성자에 @Autowired를 붙임으로써, 스프링은 스프링이 저장하고 있는 memberSevice 객체를 컨트롤러가 생성될 때 가져와 준다. 즉, 생성자에 @Autowired가 있으면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어준다. 이렇게 객체 의존관계를 외부에서 넣어주는 것을 의존성 주입(DI)라 한다.

의존성 주입의 방법

  1. 필드 주입
  2. setter 주입
  3. 생성자 주입 (권장)

생성자 주입 권장 이유

  1. 순환 의존성 확인: 필드 주입으로는 순환 의존성을 파악하기 어렵다. 생성자 주입을 하게 되면 서버 기동 시 순환 의존성을 가지는 요소들을 파악할 수 있게 에러메시지를 표시하면서 서버 기동이 되지 않는다.
  2. 불변성: 필드 주입은 final을 선언할 수 없지만 생성자 주입은 final을 선언함으로써 객체가 변하지 않도록 방지해준다.
  3. 단일 책임 원칙 위반 확인

@Autowired 어노테이션을 이용한 의존성 주입

객체 연결을 할 때 사용. 필드 혹은 생성자에 사용하면 컨트롤러, 서비스 등이 생성될 때 스프링빈에 등록되어 있는 객체를 가져다 넣어준다.

  1. 필드 주입 방법
publicclassExampleCase{

@Autowiredprivate  ChocolateService  chocolateService;

@Autowiredprivate  DrinkService  drinkService;
}
  1. 생성자 주입 방법 (권장)
publicclassExampleCase{

privatefinal  ChocolateService  chocolateService;
privatefinal  DrinkService  drinkService;

@AutowiredpublicExampleCase(ChocolateService  chocolateService, DrinkService  drinkService){
this.chocolateService = chocolateService;
this.drinkService = drinkService;
    }
}

@RequiredArgsConstructor 어노테이션을 이용한 의존성 주입

@RequiredArgsConstructor// final로 선언된 멤버 변수를 자동으로 생성합니다.@RestController// JSON으로 데이터를 주고받음을 선언합니다.publicclassProductRestController {

privatefinal ProductService productService;
privatefinal ProductRepository productRepository;

// 등록된 전체 상품 목록 조회@GetMapping("/api/products")public List<Product>getProducts() {
return productRepository.findAll();
    }
}

@RequiredArgsConstructor라는 어노테이션을 붙이면 final 필드나 @NonNull이 붙은 필드에 대해 생성자를 생성해 준다. 주로 의존성 주입의 편의성을 위해서 사용된다.

어떠한 빈(Bean)에 생성자가 오직 하나만 있고, 생성자의 파라미터 타입이 빈으로 등록 가능한 존재라면 이 빈은 @Autowired 어노테이션 없이도 의존성 주입이 가능하다.

3. AOP(관점지향 프로그래밍) 지원

관심사의 분리를 아주 스마트하고 깔끔하게 처리해준다.

스프링은 AOP를 통해 반복적인 코드를 줄이고 개발자가 핵심 비즈니스 로직에만 집중할 수 있도록 지원한다.

” 공통 관심 사항 (cross-cutting concern) vs 핵심 관심 사항 (core concern) “

비즈니스 로직은 아니지만 보안, 로그, 트랜잭션과 같이 반드시 처리가 필요한 부분을 스프링에서는 공통 관심사항이라고 한다. 예를 들어, 회원가입과 회원 조회에서 시간을 측정하는 기능은 핵심 관심 사항이 아니다. 여기서 시간을 측정하는 기능은 공통 관심 사항이다. 이들을 같은 Class 안에 메소드로 구현하면 핵심 비즈니스 로직과 공통 관심 사항에 해당하는 로직이 섞여서 유지보수가 매우 어렵다. 하지만 시간을 측정하는 로직은 별도의 공통 로직으로 만들기도 매우 어렵다. 이 경우 시간을 측정하는 로직을 변경할 때에는 모든 로직을 찾아가며 변경해야 하는 불상사가 생긴다.

https://blog.kakaocdn.net/dn/JUJjF/btq0XqxWP0H/SKJCxVlKPAEy807oCfTFSk/img.png

https://blog.kakaocdn.net/dn/4Au88/btq0Ub88sSm/HrqkeES58MiDHNfH680zOk/img.png

위의 그림과 같이 모든 Class에 시간 측정 로직을 일일히 작성해야 했지만, AOP를 사용해 아래의 그림처럼 한 번에 해결할 수 있다.

@Component@AspectpublicclassTimeTraceAop {

@Around("execution(* hello.hellospring..*(..))")public Objectexecute(ProceedingJoinPoint joinPoint)throws Throwable {
long start = System.currentTimeMillis();
        System.out.println("START: " + joinPoint.toString());
try {
return joinPoint.proceed();
        }finally {
long finish = System.currentTimeMillis();
long timeMs = finish - start;
            System.out.println("END: " + joinPoint.toString()+ " " + timeMs +
                    "ms");
        }
    }
}

AOP로 활용할 객체에는 @Aspect 어노테이션을 붙여줘야 한다.

@Around로 AOP를 적용할 객체를 지정한다. 문법을 익히면 반복되는 패턴이라 단순하다. 위는 hello.hellospring 하위 패키지에 모두 AOP 로직을 적용하라는 의미의 예시코드이다.

자, 이제 위의 문제가 해결되었다. 회원가입과 회원 조회와 같은 핵심 관심사항과 시간을 측정하는 공통 관심 사항을 분리하였다. 시간을 측정하는 로직을 별도의 공통 로직으로 만들었다. 이제 핵심 관심 사항을 깔끔하게 유지할 수 있다. 공통 관심사항 로직을 변경할 일이 생기면 AOP로 사용하는 로직의 코드만 바꾸면 된다. 심지어, 원하는 적용 대상을 선별해 적용할 수도 있게 되었다!

4. 편리한 MVC 구조

5. WAS에 독립적인 개발 환경

웹서버는 정적인 데이터를 처리하는 서버로 단순 이미지 HTML을 처리하는 서버이며, WAS(Web Application Server)는 동적인 데이터를 처리하는 서버로 DB 연동 데이터 조작등과 같은 처리를 WAS에서 한다.

스프링 Boot 기본 내장 WAS는 Apache Tomcat이다.

@SpringBootApplication을 실행하면 자동으로 웹 서버가 실행된다. 알아두어야 할 점은, 스프링 부트가 웹 서버 자체인 것은 아니다. 스프링 부트는 스프링을 편하게 사용하기 위한 툴에 불과하다. 웹 서버가 실행된다함은, 스프링 부트가 내장된 웹 서버를 자동으로 구동시킨다는 뜻이다.

스프링부트의 내장 WAS를 꼭 사용해야 하는 것은 아니고, 자유롭게 변경해 사용할 수 있다

추가로, 스프링은 개발자가 기본적인 디자인 패턴(DI, AOP, 서비스 추상화) 등을 강제적으로 사용하게끔 함으로서 코드 구조 퀄리티의 최소한을 보장하는 장점 역시 있다.

참고자료 및 출처:

스프링프레임워크: [https://kimvampa.tistory.com/35](https://kimvampa.tistory.com/35)

스프링프레임워크: [https://freestrokes.tistory.com/79](https://freestrokes.tistory.com/79)

코드로 배우는 스프링부트: [https://www.inflearn.com/course/스프링-입문-스프링부트/lecture/49577?tab=note&speed=1.25](https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8/lecture/49577?tab=note&speed=1.25)

면접 관련 스프링 키워드: [https://alswns1201.medium.com/면접-대비-및-java-관련-이론-정리-6e3f0bbe0fd5](https://alswns1201.medium.com/%EB%A9%B4%EC%A0%91-%EB%8C%80%EB%B9%84-%EB%B0%8F-java-%EA%B4%80%EB%A0%A8-%EC%9D%B4%EB%A1%A0-%EC%A0%95%EB%A6%AC-6e3f0bbe0fd5)

스프링의 장단점: [https://okky.kr/article/225553](https://okky.kr/article/225553)

@Autowired: [https://firework-ham.tistory.com/28](https://firework-ham.tistory.com/28)

@RequiredArgsConstructor: (https://webdevtechblog.com/requiredargsconstructor-%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-dependency-injection-4f1b0ac33561)

스프링과 빈의 의존관계: (https://no-delay-code.tistory.com/61)

MVC: (https://iri-kang.tistory.com/4)

comments powered by Disqus