1. 개념
어떤 서비스를 개발한다고 생각해보자. 특정 서비스에는 다양한 기능들이 있고, 다양한 기능을 개발하기 위해서는 다양한 클래스가 필요하다. 기능 별로(로그인, 회원가입, 글 작성 등) 클래스가 분류될 것이고, 그 기능 안에서 service, controller, repository, entity 등 세부 기능으로 또 클래스가 분류된다. 이렇듯 우리는 스프링으로 서비스를 개발할 때 아주아주 다양한 클래스를 접하게 된다. 나는 앞으로 class 하나 하나를 컴포넌트라고 이야기 하려고 한다.
예를 들어 회원가입 기능을 생각해보자. 이를 위해서는 controller, service, repository, passwordEncoder 등의 컴포넌트가 필요하다. controller는 service컴포넌트가 필요하고, service는 repository와 passwordEncoder 컴포넌트가 필요하다. 이렇듯 다른 class에서 다른 class(컴포넌트)를 필요로 하는 것을 의존성이라고 한다. 그리고 이러한 의존성을 가능하게 해야 기능 개발이 가능하기 때문에, 우리는 controller에서 service 컴포넌트 의존성을 주입해야 한다. 이것이 의존성 주입의 개념이다.
2. DI 컨테이너
1) 개념
DI 컨테이너는 의존성 주입을 쉽고 효율적으로 할 수 있게 해 주는 개념이다. 무려 스프링에서 의존성 주입을 자동으로 해 준다!
먼저, DI 컨테이너가 없을 때의 경우를 생각해보자. service 클래스를 작성할 때 repository와 passwordEncoder를 생성하고, 생성한 것을 service 클래스의 인스턴스 변수에 할당할 수 있다. 이러면 의존성 주입이 가능하긴 하지만, service가 개발 될 때 무조건 repository와 passwordEncoder가 완성되어 있어야 한다. 다양한 의존성 주입을 하다 보면 완성되지 않은 상태에서 의존성 주입이 일어날 수도 있고, service에서 repository와passwordEncoder가 생성되고 나면 2개를 교체하는 것이 어렵게 된다. 이러한 클래스의 관계를 클래스 간의 결합도가 높다고 하는데, 결합도가 높은 경우 비효율적인 상황이 발생할 가능성이 높다.
또 다른 방법으로는 service 클래스의 생성자 변수로 repository와 passwordEncoder를 받을 수 있다. 이 경우, 아직 repository와 passwordEncoder가 완성되지 않았을 때 더미 인스턴스를 넘겨주면 되기 때문에 문제가 해결되는 측면이 있다. 하지만, 여전히 더미든 더미가 아니든 개발자가 직접 생성해서 넣어줘야 하는 비효율적인 측면이 남아 있다.
DI 컨테이너는 이러한 문제를 해결해 준다. 스프링에서 제공하는 컨테이너에 다양한 컴포넌트의 존재와, 컴포넌트들 끼리의 의존 관계를 알려주면 특정 컴포넌트가 생성될 때, 그 컴포넌트에서 필요한 의존성들을 자동으로 가져와 주는 것이다.
3. 방법
0) @Autowired
의존성에 맞는 빈을 찾아 DI 컨테이너에 주입하기 위해 사용하는 어노테이션
1) 생성자 주입
생성자 메서드의 매개변수로 의존성을 주입하는 방법
@Service
public class userService{
private UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository){
this.userRepository = userRepository;
}
}
특징
- 필드를 final로 선언해서 생성 후에 변경되지 않도록 설정할 수 있다. 이 기능은 생성자 주입에서만 가능하다.
- 가장 권장되는 방법
2) 필드 주입
메서드를 사용하지 않고 DI 컨테이너의 힘을 빌려 의존성을 주입.
@Service
public class UserService{
@Autowired
private UserRepository userRepository;
}
특징
- 반드시 DI 컨테이너를 사용한다는 사실이 전제되어야 한다.
3) 설정자 주입
흔히 말하는 setter의 방식으로 의존성을 주입하는 것을 의미한다.
@Service
public class userService{
private UserRepository userRepository;
@Autowired
public void setUserRepository(UserRepository userRepository){
this.userRepository = userRepository;
}
}
특징
- 주입되는 인스턴스가 변경될 가능성이 있는 경우 사용
'Spring > spring' 카테고리의 다른 글
[스프링] controller 관련 어노테이션 (0) | 2023.02.22 |
---|---|
[스프링] service 관련 어노테이션 (0) | 2023.02.22 |