백앤드(Back-End)/Spring Boot

[Spring Boot] 구조 분석 (4) - 의존관계 주입 방식

RyanSin 2023. 4. 16. 23:47
반응형

- 지난 시간

안녕하세요. 지난 시간에는 @Autowired 어노테이션에 대해 알아봤습니다. 놓고 오신 분들은 아래 링크를 통해 학습하고 오시는 걸 추천드리겠습니다.

[Spring Boot] 구조 분석 (3) - @Autowired(의존관계 주입)

 

[Spring Boot] 구조 분석 (3) - @Autowired(의존관계 주입)

- 지난 시간 안녕하세요. 지난 시간에는 Spring Container에 대해 알아봤습니다. 놓치고 오신 분들은 아래 링크를 통해 학습하고 오시는 걸 추천드리겠습니다. [Spring Boot] 구조 분석 (2) - 스프링 컨테

any-ting.tistory.com

 

- 개요

이번 시간에는 의존관계 주입을 하는 방식에 대해 알아보겠습니다. 방식을 알아보기 전에 몇 가지 개념을 다시 한번 짚고 넘어가겠습니다. 

 

DI(Dependency Injection) 프레임워크인 Spring Boot 프레임워크에는 Container라는 개념이 존재합니다.

 

해당 Container에는 우리가 사용할 클래스를 미리 생성해서 싱글톤으로 관리합니다.

 

우리가 생성하고 싶은 클래스를 Container의 등록을 하기 위해서는 @Componet, @Controller, @RestController, @Service, @Repository와 같은 어노테이션을 사용하면 Bean으로 해당 클래스를 생성해 Container의 등록합니다.

 

 

또한, @Componet 어노테이션이 최상위 어노테이션이기 때문에 다른 어노테이션이 등록을 할 수 있게 됩니다.

 

선언방법 - 작성한 클래스 위의 @어노테이션을 선언하면 됩니다.

@RestController
@RequestMapping("/user")
public class UserController {
	...
}


===============================

@Service
public class UserService {
	...
}

 

만약 다른 방법을 원한다면, @Configuration 어노테이션을 활용해 @Bean으로 우리가 작성한 클래스를 등록합니다.

package com.ryan.spring_boot_rest_api.config;

import com.ryan.spring_boot_rest_api.repository.UserMemoryRepository;
import com.ryan.spring_boot_rest_api.repository.UserRepositoryInterface;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {
    @Bean
    public UserRepositoryInterface userRepository(){
        return new UserMemoryRepository();
    }
}

 

자 여기까지 개념을 이해하셨다면 이제 등록된 클래스를 불러와서 사용해야겠죠?

 

등록된 클래스를 불러와서 사용하는 방식에 대해 설명하도록 하겠습니다.

 

- 의존관계 주입 방식

  1. 생성자 주입 또는 @RequiredArgsConstructor
  2. 수정 메소드를 통한 주입(setter 주입)
  3. 필드 주입
  4. 일반 메서드 주입

- 생성자 주입 또는 @RequiredArgsConstructor

생성자 주입이란 클래스가 생성되는 시점에 의존관계를 설정하고 주입하는 방식을 뜻 합니다.

@Service
public class UserService {

    private UserRepositoryInterface userRepository;

    private UserDiskRepository userDiskRepository;

    @Autowired
    public UserService(UserRepositoryInterface userRepository, UserDiskRepository userDiskRepository) {
        this.userRepository = userRepository;
        this.userDiskRepository = userDiskRepository;
    }
    
    ...
}

지난 시간에 @Autowired 어노테이션에 대해 설명했습니다. 해당 어노테이션은 의존관계를 주입할 때 사용된다고 설명했습니다.

 

위 코드를 확인하면 생성자 메서드 위의 @Autowired를 선언한 걸 확인할 수 있습니다.

 

이렇게 되면 해당 클래스가 생성될 때 딱 한 번만 의존관계를 주입합니다.

 

@RequiredArgsConstructor 어노테이션

@RequiredArgsConstructor 어노테이션은 위 코드를 조금 더 간결하게 만들며 생성자 주입을 할 때 사용됩니다.

@Service
@RequiredArgsConstructor
public class UserService {

    private final UserRepositoryInterface userRepository;

    private final UserDiskRepository userDiskRepository;
 
    ...
}

 

반드시 final을 정의해줘야 합니다. final 키워드는 처음 정의된 상태가 변하지 않도록 보장합니다. 즉, 우리가 생성자 주입의 특징처럼 처음 클래스가 생성될 때 딱 한 번만 의존관계를 정의하고 더 이상 변하지 않게 합니다.

 

참조 값을 변경하지 못하도록 하기 때문에 불변성을 확보할 수 있습니다.

 

- 수정 메서드를 통한 주입(setter 주입)

말 그대로 수정자 setter 메소드를 통해서 주입하는 방식입니다. setter 방식은 보편적으로 사용하지 않습니다.

왜냐하면 변경 됐을 때 문제가 많이 발생하기 때문에 보편적으로 개발할 때 사용하지 않습니다.

@Service
public class UserService {

    private UserRepositoryInterface userRepository;

    private UserDiskRepository userDiskRepository;

    @Autowired
    public void setUserDiskRepository(UserDiskRepository userDiskRepository) {
        this.userDiskRepository = userDiskRepository;
    }
    
    ...
}

 

- 필드 주입

필드 주입은 필드변수에 바로 의존관계를 설정하는 겁니다.

@Service
public class UserService {

    @Autowired
    private UserRepositoryInterface userRepository;

    @Autowired
    private UserDiskRepository userDiskRepository;
 	
    ...   
}

간편하고 가독성도 좋긴 하지만... Spring Boot에서는 선호하지 않는 방식입니다.

생성자 주입으로 선언을 권장하고 있습니다.

 

- 일반 메서드 주입

일반 메서드 주입은 말 그대로 우리가 선언한 메서드를 통해 주입하는 방식입니다. (수정자 주입과 동일한 방식이기 때문에... 해당 방식도 문제가 많이 발생 상황이 생깁니다.)

@Service
public class UserService {

    private UserRepositoryInterface userRepository;

    private UserDiskRepository userDiskRepository;

    @Autowired
    public void init(UserDiskRepository userRepository) {
        this.userDiskRepository = userRepository;
    }
    
    ...
    
}

 

Java 언어를 익숙하신 분들은 위 내용을 이해하기 편할 것 같아요. 뭐 당연한 소리를 하나라고 생각하겠지만... 저는 보통 기술을 습득하는 데 있어서 오래 걸리는 상황이 발생하면 항상 기초가 문제였던 것 같아요... 결국 다시 보고 또 봐야 내 것이 되는 것 같아요!

 

여러분도 꼭 위 예제를 통해 실제 실습하시는 걸 추천드려요!