ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ๋ค ๋ณด๋ฉด ์์ฐ์ค๋ฝ๊ฒ ์ฐ๊ฒ ๋์ง๋ง ๋ง์ DI๊ฐ ๋ฌด์์ธ์ง ๋ช ํํ ์ค๋ช ํ๊ธฐ ์ ๋งคํ ๊ฒฝ์ฐ๋ ๋ง๋ค. ์ด๋ฒ ๊ธ์์๋ DI๊ฐ ๋ฌด์์ธ์ง, ์ ์ฐ๋์ง, ๊ทธ๋ฆฌ๊ณ ์ค์ ์ฝ๋์์๋ ์ด๋ป๊ฒ ์ฌ์ฉ๋๋์ง ์์๋ณด์.
ํ์ํ ๊ฐ์ฒด๋ฅผ ๋ด๊ฐ ์ง์ new ํ์ง ์๊ณ ์ธ๋ถ์์ ๋ฃ์ด ์ฃผ๋๋ก ๋ง๋๋ ๊ฒ์ ์๋ฏธํ๋ค.
์๋ฅผ ๋ค์ด A ํด๋์ค์์ B ํด๋์ค๋ฅผ ํ์๋ก ํ ๋ A ํด๋์ค ๋ด๋ถ์์ new ํค์๋๋ฅผ ์ฌ์ฉํ์ฌ ์ง์ ์์ฑํ๋ ๋์ ํ๋ ์์ํฌ(์คํ๋ง, NestJS ๋ฑ)์ ์ปจํ
์ด๋๊ฐ B ํด๋์ค๋ฅผ A์ ์ฃผ์
ํด ์ฃผ๋ ๋ฐฉ์์ด๋ค.
์์กด์ฑ(Dependency)์ ์ธ๋ถ์์ ์ฃผ์
(Injection) ํ๋ค๋ ์๋ฏธ
๊ทธ๋ฅ ๊ฐ์ฒด ๋ด๋ถ์์ new ํด์ ์ฌ์ฉํ๋ฉด ๋๋ ๊ฒ ์๋๊ฐ?๋ผ๋ ์๊ฐ์ด ๋ค ์๋ ์์ง๋ง DI๋ฅผ ์ฌ์ฉํ์ ๋์ ์ฅ์ ๋ค์ด ์๋ค.
๋จผ์ DI๊ฐ ์๋ ์ฝ๋๋ฅผ ๋ณด๋ฉด
// DI๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ์ง์ ์์ฑ
public class PostService {
private final PostRepository postRepository = new PostRepository();
public Post getPost(Long id) {
return postRepository.findById(id);
}
}
์ด๋ฐ ๊ฒฝ์ฐ ํ
์คํธํ ๋ ๋ช ๊ฐ์ง ๋ฌธ์ ๊ฐ ์กด์ฌํ๋ ๋ฐ ์๋ฅผ ๋ค์ด PostRepository๊ฐ DB์ ์ง์ ๋ถ๋ ๊ตฌํ์ฒด๋ผ๋ฉด ๋จ์ ํ
์คํธ๋ง๋ค ์ค์ DB๋ฅผ ํ์๋ก ํ์ฌ Mock(๊ฐ์ง ๊ฐ์ฒด)๋ก ๋ณ๊ฒฝํ๊ธฐ๊ฐ ์ด๋ ต๋ค.
๋ฐ๋ผ์ DI๋ฅผ ์ ์ฉํ๋ฉด ์๋์ ๊ฐ๋ค.
// DI ์ ์ฉ
public class PostService {
private final PostRepository postRepository;
public PostService(PostRepository postRepository) {
this.postRepository = postRepository; // ์ธ๋ถ์์ ์ฃผ์
}
public Post getPost(Long id) {
return postRepository.findById(id);
}
}
์ด์ ํ
์คํธ ์์๋ ์๋์ ๊ฐ์ด Mock ๊ฐ์ฒด๋ฅผ ์ฃผ์
ํ ์ ์๋ค.
PostRepository mockRepo = mock(PostRepository.class);
PostService postService = new PostService(mockRepo);
์ค์ DB๋ฅผ ๋ถ์ด์ง ์๊ณ ๋ Mock ๊ฐ์ฒด๋ฅผ ์ฃผ์
ํด์ PostService๋ฅผ ์์ํ๊ฒ ํ
์คํธํ ์ ์๋ค.
DI์ ํต์ฌ์ ์ถ์ ํ์ (์ธํฐํ์ด์ค)์ ์์กดํ๋ผ๋ ์์น๊ณผ ์ ๋ง๋๋ค. ์๋ฅผ ๋ค์ด ์ ๋๊ธ์ด ๋ฌ๋ฆฌ๋ฉด ๊ธ ์์ฑ์์๊ฒ ์๋ฆผ์ ๋ณด๋ด๋ ๊ธฐ๋ฅ์ ๋ง๋ ๋ค๊ณ ์๊ฐํด ๋ณด์. ์ฒ์์๋ ์ด๋ฉ์ผ๋ง ๋ณด๋ด๋ฉด ๋๋ค๊ณ ์๊ฐํด์ ์๋์ ๊ฐ์ด ์ธํฐํ์ด์ค๋ฅผ ์ ์ํ ์ ์๋ค.
// ์๋ฆผ ์ธํฐํ์ด์ค
public interface BlogNotifier {
void notifyNewComment(Long postId, String commentAuthor, String commentContent);
}
// ์ด๋ฉ์ผ ์๋ฆผ ๊ตฌํ์ฒด
public class EmailBlogNotifier implements BlogNotifier {
@Override
public void notifyNewComment(
Long postId, String commentAuthor, String, commentContent
) {
// ์ด๋ฉ์ผ ์ ์ก ๋ก์ง
}
}
๊ทธ๋ฐ๋ฐ ๋ธ๋ก๊ทธ๋ฅผ ์ด์ํ๋ ๋์ค ์๊ตฌ์ฌํญ์ด ๋ฐ๋์ด ์ฌ๋์ผ๋ก ์๋ฆผ์ ๋ณด๋ด์ผ ํ๋ ๊ฒฝ์ฐ๋ผ๋ฉด ์๋์ ๊ฐ์ด ์ฌ๋ ์๋ฆผ ๊ตฌํ์ฒด๋ฅผ ๋ง๋ค๋ฉด ๋๋ค.
// ์ฌ๋ ์๋ฆผ ๊ตฌํ์ฒด
public class SlackBlogNotifier implements BlogNotifier {
@Override
public void notifyNewComment(
Long postId, String commentAuthor, String commentContent
) {
// ์ฌ๋ ์๋ฆผ ์ ์ก ๋ก์ง
}
}
์ฌ๊ธฐ์ ์ค์ํ ํฌ์ธํธ๋ CommentService ์ฝ๋๋ ๋ณ๊ฒฝํ์ง ์๊ณ ๋จ์ง DI ์ค์ ์์ ์ด๋ค ๊ตฌํ์ฒด๋ฅผ ์ฃผ์
ํ ์ง๋ง ๊ฒฐ์ ํ๋ฉด ๋๋ค๋ ์ ์ด๋ค. ์๋ฅผ ๋ค์ด ์คํ๋ง์ด๋ผ๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์ค์ ํ ์ ์๋ค.
@Configuration
public class BlogConfig {
@Bean
public BlogNotifier blogNotifier() {
// ์ํฉ์ ๋ง๋ ๊ตฌํ์ฒด๋ฅผ ์ ํ
// return new EmailBlogNotifier();
return new SlackBlogNotifier();
// ํ์ํ ๊ฒฝ์ฐ Email + Slack์ ๋ฌถ์ Composite ๊ตฌํ์ฒด๋ฅผ ๋ง๋๋๊ฒ๋ ๊ฐ๋ฅ
}
@Bean
public CommentService commentService(BlogNotifier blogNotifier) {
return new CommentService(blogNotifier);
}
}
์ด๋ ๊ฒ ํ๋ฉด CommentService๋ ์ค์ง BlogNotifier ์ธํฐํ์ด์ค๋ง ์์กดํ๋ค. ์ค์ ๋ก ์ด๋ฉ์ผ์ ๋ณด๋ผ์ง ์ฌ๋์ ๋ณด๋ผ์ง๋ ์ปจํ
์ด๋ ์ค์ ์์ ๊ฒฐ์ ํ์ฌ ๋์ค์ WebPush, ์นด์นด์คํก ์๋ฆผ ๋ฑ์ ์ถ๊ฐํ๊ณ ์ถ์ด๋ ์๋ก์ด ๊ตฌํ์ฒด๋ฅผ ๋ง๋ค๊ณ DI ์ค์ ๋ง ๋ฐ๊พธ๋ฉด ๋๊ธฐ ๋๋ฌธ์ ์ ์ง ๋ณด์์ ํ์ฅ์ด ํจ์ฌ ์ฌ์์ง๋ค.
DI๊ฐ ๋์ค๋ฉด ํญ์ ๋ฐ๋ผ์ค๋ ๋จ์ด๊ฐ ํ๋ ๋ ์๋ค. ๋ฐ๋ก IoC(Inversion of Control) ์ ์ด์ ์ญ์ ์ด๋ค. ๊ธฐ์กด ์ ํต์ ์ธ ๋ฐฉ์์์๋ ๋๊ฐ ์ด๋ค ๊ฐ์ฒด๋ฅผ new ํ ์ง, ๋๊ฐ ๋๊ตฌ๋ฅผ ํธ์ถํ ์ง ์ ๋ถ ๋ด ์ฝ๋๊ฐ ์ง์ ์ ์ดํ๋ค.
public class Main {
public static void main(String[] args) {
PostRepository repo = new PostRepository();
PostService service = new PostService(repo);
Post post = service.getPost(1L);
}
}
์ ์ฝ๋์์๋ ์ง์ ๊ฐ์ฒด ์์ฑ ์์์ ์์กด์ฑ์ ๋ชจ๋ ์ ์ดํ๊ณ ์๋ค. ๊ทธ๋ฌ๋ ์คํ๋ง, NestJS ๊ฐ์ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฐ์ฒด๋ฅผ ์ธ์ ๋ง๋ค์ง, ์ด๋ค ์์๋ก ๋ง๋ค์ง, ์ด๋ค ๊ฐ์ฒด์ ์ด๋ค ์์กด์ฑ์ ์ฃผ์
ํ ์ง ๊ฐ์ ์ด๋ฐ ์ ์ด๊ถ์ ํ๋ ์์ํฌ์ IoC ์ปจํ
์ด๋๊ฐ ๊ฐ์ ธ๊ฐ๋ค.
์ฐ๋ฆฌ๋ ๊ทธ์ ์ด ํด๋์ค๊ฐ ์๋น์ค์ธ์ง ๋ ํฌ์งํ ๋ฆฌ์ธ์ง ํน์ ์ฃผ์
๋ฐ์ ์ฌ์ฉํ ์ง ๋ฑ์ ์ฌ๋ถ๋ง ์ด๋
ธํ
์ด์
์ ํตํด ํ์ํด ์ฃผ๋ฉด ๋๋ค.
@Repository
public class PostRepository {
// ๋ ํฌ์งํ ๋ฆฌ ์ฝ๋
}
@Service
public class PostService {
private final PostRepository postRepository;
@Autowired
public PostService(PostRepository postRepository) {
this.postRepository = postRepository;
}
}
์ง์ new ํ์ง ์๊ณ ์ปจํ
์ด๋๊ฐ ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ ์ฃผ์
ํ๋ค. ์ฆ ์ ์ด(Control)๊ฐ ์ฐ๋ฆฌ ์ฝ๋์์ ํ๋ ์์ํฌ๋ก ์ญ์ (Inversion) ๋์๋ค. ์ด๊ฒ์ IoC๋ผ๊ณ ํ๋ฉฐ ๊ทธ ๊ตฌ์ฒด์ ์ธ ๋ฐฉ๋ฒ ์ค ํ๋๊ฐ DI์ด๋ค.
DI์๋ ๋ณดํต ์ธ ๊ฐ์ง ๋ฐฉ์์ด ์๋ค.
์์ฆ์ ์์ฑ์ ์ฃผ์
์ด ๊ฐ์ฅ ๊ถ์ฅ๋๋ ๋ฐฉ์์ด๋ค.
*์์ฑ์ ์ฃผ์
@Service
public class PostService {
private final PostRepository postRepository;
public PostService(PostRepository postRepository) {
this.postRepository = postRepository;
}
}
final ํ๋๋ฅผ ์ฌ์ฉํ ์ ์์ด ๋ถ๋ณ์ฑ์ ์งํฌ ์ ์์ผ๋ฉฐ ํ
์คํธ ์ฝ๋์์ ์์ฑ์๋ง ํธ์ถํ๋ฉด ๋๊ธฐ ๋๋ฌธ์ ํ
์คํธ๋ ์ฉ์ดํ๋ค. (Lombok ์ฌ์ฉ ์ @RequiredArgsConstructor๋ก๋ ๊ฐ๋ฅ)
*ํ๋ ์ฃผ์
@Service
public class PostService {
@Autowired
private PostRepository postRepository;
}
์ฝ๋๊ฐ ๊ต์ฅํ ๊ฐ๋จํด์ง์ง๋ง ํ๋๊ฐ final์ด ๋ ์ ์๊ณ ํ
์คํธ ์ Mock ์ฃผ์
์ด ๋ถํธํ์ฌ ์์ฆ์ ์ง์ํ๋ ๋ฐฉ์์ผ๋ก ์ทจ๊ธ๋๋ค. (DI ์ปจํ
์ด๋ ์์ด ์์ ์๋ฐ ์ฝ๋๋ก ์์ฑํ๊ธฐ๋ ์ด๋ ต๋ค)
*์ธํฐ ์ฃผ์
@Service
public class PostService {
private PostRepository postRepository;
@Autowired
public void setPostRepository(PostRepository postRepository) {
this.postRepository = postRepository;
}
}
์ ํ์ ์ธ ์์กด์ฑ์ด๋ ๋ฐํ์์ ๊ตฌํ์ฒด๊ฐ ๋ฐ๋ ์ ์๋ ๊ฒฝ์ฐ์ ์ฌ์ฉ๋๊ธฐ๋ ํ์ง๋ง ์ผ๋ฐ์ ์ธ ์๋น์ค/๋ ํฌ์งํ ๋ฆฌ ๊ตฌ์กฐ์์๋ ์์ฑ์ ์ฃผ์
์ด ๋ ๊น๋ํ๋ค.
