-
[SpringBoot] ์คํ๋ง Bean๊ณผ ์์กด์ฑ ์ฃผ์ (Dependency Injection) feat: ์ปดํฌ๋ํธ ์ค์บ๊ณผ ์ฑ๊ธํค ํจํด, ์ ์ด์ ์ญ์ ๐ปProgramming/SpringBoot 2024. 3. 12. 21:36
Bean
์คํ๋ง ์ปจํ ์ด๋์ ์ํด ๊ด๋ฆฌ๋๋ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์ํํธ์จ์ด ์ปดํฌ๋ํธ(component)๋ก, ์คํ๋ง ์ปจํ ์ด๋๊ฐ ๊ด๋ฆฌํ๋ ์๋ฐ ๊ฐ์ฒด๋ฅผ ๋ปํ๋ค.
์์กด์ฑ ์ฃผ์ ์ด๋?
๋ณดํต ์คํ๋ง์์๋ controller ํด๋์ค์์ ์์ฒญ์ ๋ฐ๊ณ , ํด๋น ์์ฒญ์ ๋ํ ๋น์ฆ๋์ค ๋ก์ง์ ๋ํ ์ฒ๋ฆฌ๋ service ํด๋์ค์์ ๊ตฌํํ๊ณ , ์ด ๋น์ฆ๋์ค ๋ก์ง์์ ํ์ํ ๋ฐ์ดํฐ ์ ๊ทผ์๋ repository ํด๋์ค์์ ์ฒ๋ฆฌ๋ฅผ ํ๋ค. ์ด ๊ฒฝ์ฐ controller๋ service์ ์์กดํ๊ณ , service๋ repository์ ์์กดํ๋ ํ์์ผ๋ก ์ผ๋ฐ์ ์ผ๋ก ์คํ๋ง๋ถํธ ํ๋ก์ ํธ๊ฐ ๊ตฌ์ฑ๋๋ค.
์๋ฅผ ๋ค์ด,
public class MemberController { private final MemberService memberService; public MemberController() { this.memberService = new MemberService(); } }
์ด ์ฝ๋์์ MemberController๋ MemberService์ ์์กดํ๊ณ ์๋ค. ์ด ์ฝ๋์ ๋ฌธ์ ์ ์ ๋ฌด์์ผ๊น?
- ๋ "ํด๋์ค"๊ฐ ๊ฐํ๊ฒ ๊ฒฐํฉ๋์ด ์๋ค.
- ๊ฐ์ฒด๋ค ๊ฐ์ ๊ด๊ณ๊ฐ ์๋๋ผ ํด๋์ค ๊ฐ์ ๊ด๊ณ๊ฐ ๋งบ์ด์ ธ์๋ค.
์ด ๋ฌธ์ ๋ฅผ ์ด๋ป๊ฒ ํด๊ฒฐํ ์ ์์๊น?
์ธ๋ถ์์ MemberService๋ฅผ ์ฃผ์ (Injection)๋ฐ์์ผ ํ๋ค.
public class MemberController { private final MemberService memberService; public MemberController(MemberService memberService) { this.memberService = memberService; } }
์ ๊ฐ์ด memberService๊ฐ์ฒด๋ฅผ ๋ฐ์ MemberController ๊ฐ์ฒด๋ก ์ฃผ์ ํ๋ค.
๋ฐ๋ผ์ ์ฐ๋ฆฌ๋ Spring์ด๋ผ๋ DI(Dependency Injection, ์์กด์ฑ ์ฃผ์ ) ์ปจํ ์ด๋๋ฅผ ํ์๋ก ํ๋ค. ์ ํ๋ฆฌ์ผ์ด์ ์ ์คํ ์์ ์ ํ์ํ ๊ฐ์ฒด=๋น์ ์์ฑํด์ผ ํ๋ฉฐ, ์์กด์ฑ์ด ์๋ ๋ ๊ฐ์ฒด๋ฅผ ์ฐ๊ฒฐํ๊ธฐ ์ํ ํ ๊ฐ์ฒด๋ฅผ ๋ค๋ฅธ ๊ฐ์ฒด๋ก ์ฃผ์ ์์ผ์ผ ํ๋ค.
์คํ๋ง์์ ์์ฑ์์ @Autowired๊ฐ ์กด์ฌํ๋ฉด,์คํ๋ง์ด ์ฐ๊ด๋ ๊ฐ์ฒด๋ฅผ ์คํ๋ง ์ปจํ ์ด๋์์ ์ฐพ์์ ๋ฃ์ด์ฃผ๋ ๋ฐฉ์์ผ๋ก ์์กด์ฑ ์ฃผ์ ์ ํ๋ค. ๋ฐ๋ก ์์ ์ฝ๋์์ ๊ฐ๋ฐ์๊ฐ ์ง์ ์์กด์ฑ ์ฃผ์ ์ ํด์ค ๊ฒ์ด๊ณ , @Autowired๋ฅผ ์ฌ์ฉํ๋ฉด ์คํ๋ง์์ ์๋์ผ๋ก ๊ฐ์ฒด์ ์์กด๊ด๊ณ๋ฅผ ์ธ๋ถ์์ ๋ฃ์ด์ค๋ค. ํ์ง๋ง ์ด ์์กด์ฑ์ ๋ฃ์ด์ฃผ๊ธฐ ์ํ ๊ฐ์ฒด๋ ์คํ๋ง ์ปจํ ์ด๋์ ๋ฑ๋ก๋์ด์์ด์ผ ์์กด์ฑ์ ๋ฃ์ด์ค ์ ์๊ธฐ ๋๋ฌธ์,
@Controller public class MemberController { private final MemberService memberService; @Autowired public MemberController(MemberService memberService) { this.memberService = memberService; } }
MemberService ํด๋์ค๋ ๋น์ผ๋ก ๋ฑ๋ก, MemberController๋ ๋ฌผ๋ก ๋น์ผ๋ก ๋ฑ๋ก๋์ด ์์ด์ผ ํ๋ค. ์คํ๋ง์ ์คํ๋ง ์ปจํ ์ด๋์ ๋ฑ๋ก๋ ๋น=๊ฐ์ฒด๋ค์ ๊ด๋ฆฌํ๊ธฐ ๋๋ฌธ์ด๋ค. ๋ํ ์ด๋ ๊ฒ ์คํ๋ง์ด ์๋์ผ๋ก ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๊ฐ์ฒด๋ค์ ์์กด ๊ด๊ณ๊น์ง ์ค์ ํด์ฃผ๋ ๊ฐ๋ ์ "์ ์ด์ ์ญ์ (Inversion of Control, IoC)"์ด๋ผ๊ณ ๋ ํ๋ค. ๊ฐ๋ฐ์๊ฐ ๊ฐ์ฒด์ ๊ด๊ณ๋ฅผ ๊ด๋ฆฌํ๊ณ , ๊ฐ์ฒด๋ฅผ ๊ด๋ฆฌํ๋ ๊ฒ์ด ์๋ ์คํ๋ง ์ปจํ ์ด๋๊ฐ ๊ด๋ฆฌํด์ค์ผ๋ก์จ ์ ์ด๊ฐ ์ญ์ ๋์๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค.
์์กด์ฑ ์ฃผ์ ๋ฐฉ๋ฒ 3๊ฐ์ง
1. ํ๋ ์ฃผ์ (๊ถ์ฅ x)
@Controller public class MemberController { @Autowired MemberService memberService; }
์ฝ๋๊ฐ ๊ฐ๊ฒฐํ์ง๋ง, ์ธ๋ถ์์ ๋ณ๊ฒฝ์ด ๋ถ๊ฐ๋ฅํด์ ํ ์คํธํ๊ธฐ ํ๋ค๋ค๋ ์น๋ช ์ ์ธ ๋จ์ ์กด์ฌ.
DI ํ๋ ์์ํฌ๊ฐ ์์ผ๋ฉด ์ด๋ค ๊ฒ๋ ๋ถ๊ฐ๋ฅ
2. setter ์ฃผ์
@Controller public class MemberController { private MemberService memberService; @Autowired public void setMemberService(MemberService memberService) { this.memberService = memberService; } }
๋จ์ : public์ผ๋ก ์ ์ธํ์ฌ ์ธ๋ถ ํด๋์ค์์ ์ ๊ทผํ๊ณ ๋ณ๊ฒฝ ๊ฐ๋ฅ. ์์กด ๊ด๊ณ๋ ํ๋ก์ ํธ ์์๋ถํฐ ๋๊น์ง ๋ถ๋ณํ์ฌ์ผ ๋ง๋ค. ๋์ค์ ๋ฐ๊ฟ์ผ์ด ์๋๋ก ์ค๊ณํ์ฌ์ผ ํ๊ธฐ ๋๋ฌธ์ ๊ถ์ฅ๋์ง ์๋๋ค.
3. ์์ฑ์ ์ฃผ์ (๊ถ์ฅ)
@Controller public class MemberController { private MemberService memberService; @Autowired public MemberController(MemberService memberService) { this.memberService = memberService; } }
์ฅ์ : ์์ฑํ๋ ์์ ์๋ง ์์ฑ์ด ๋๊ณ , ์ดํ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅ.
- ๋ถ๋ณ, ํ์์ธ ์์กด ๊ด๊ณ์ ์ฌ์ฉ๋๋ค.
- ํ๋๋ฅผ final๋ก ์ ์ธํ์ฌ ์์ ๋ถ๊ฐ๋ฅํ๊ฒ ํ ์ ์๋ค. -> ์์ฑ์์์ ํน์๋ผ๋ ๊ฐ์ด ์ค์ ๋์ง ์๋ ์ค๋ฅ๋ฅผ "์ปดํ์ผ ์์ "์ ๋ง์์ค๋ค.
- ์์์ ๋งํ๋ฏ์ด ๋๋ถ๋ถ์ ์์กด๊ด๊ณ ์ฃผ์ ์ ํ ๋ฒ ์ผ์ด๋๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์ ์ข ๋ฃ ์์ ๊น์ง ์์กด๊ด๊ณ๋ฅผ ๋ณ๊ฒฝํ ์ผ์ด ์์ด์ผ ํ๋ค. -> ๋ถ๋ณํด์ผํ๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์คํ๋ง์์๋ ์ด ์์กด๊ด๊ณ ์ฃผ์ ์ ๊ถ์ฅํ๋ ๊ฒ.!!
- *์ฐธ๊ณ : ์์ฑ์ ์ฃผ์ ์ ํตํด ์์กด๊ด๊ณ๋ฅผ ์ฃผ์ ํ ๊ฒฝ์ฐ ์์ฑ์๊ฐ ํด๋์ค์ ํ๊ฐ๋ง ์๋ค๋ฉด ์คํ๋ง์์ ์๋์ผ๋ก @Autowired ์ด๋ ธํ ์ด์ ์ ๋ถ์ฌ์ค๋ค.
- ๋ํ, ํ ์คํธ์ ์ํ๋ ๊ฐ์ฒด๋ฅผ ๋ฐ๊ฟ ๋ผ์๊ฐ๋ฉฐ ํ ์คํธ ๊ฐ๋ฅ
@Test void createOrder() { MemoryMemberRepository memberRepository = new MemoryMemberRepository(); memberRepository.save(new Member(1L, "name", Grade.VIP)); OrderServiceImpl orderService = new OrderServiceImpl(memberRepository, new FixDiscountPolicy()); Order order = orderService.createOrder(1L, "itemA", 10000); Assertions.assertThat(order.getDiscountPrice()).isEqualTo(1000); }
์์ฑ์ ์ฃผ์ ์ ๋ ๊ฐ๊ฒฐํ๊ณ ๊น๋ํ๊ฒ ํ๋ ๋ฐฉ๋ฒ์๋ ๋ญ๊ฐ ์์๊น?
@Component @RequiredArgsConstructor // ์์ฑ์ ์๋ ์์ฑ public class OrderServiceImpl implements OrderService { private final MemberRepository memberRepository; private final DiscountPolicy discountPolicy; @Override public Order createOrder(Long memberId, String itemName, int itemPrice) { Member member = memberRepository.findById(memberId); int discountPrice = discountPolicy.discount(member, itemPrice); return new Order(memberId, itemName, itemPrice, discountPrice); } public MemberRepository getMemberRepository() { return memberRepository; } }
์ ๊ฐ์ด ์ฌ์ฉ ๊ฐ๋ฅํ๋ฉด ๋งค์ฐ ๊ฐ๊ฒฐํ๊ฒ ์ฝ๋๋ฅผ ์์ฑํ๊ณ , ์์ฑ์ ์ฃผ์ ์ ํตํ ์์กด๊ด๊ณ ์ฃผ์ ์ด ๊ฐ๋ฅํด์ง๋ค.
@RequiredArgsConstructor
์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ์ฌ ์์ฑ์๋ฅผ ๊ฐํธํ๊ฒ ์์ฑํ ์ ์๋ค. "final์ด ๋ถ์ ํ๋"๋ฅผ ๋ชจ์์ ์์ฑ์๋ฅผ ์๋์ผ๋ก ๋ง๋ค์ด์ค๋ค.
์ ์ฝ๋์ ๊ฒฝ์ฐ ์์ฑ์๋ 1๊ฐ์ด๋ ์๋์ผ๋ก @Autowired๊ฐ ๋๋ค.
์ต๊ทผ์๋ ์์ฑ์๋ฅผ 1๊ฐ ๋๊ณ , @Autowired๋ฅผ ์๋ตํ๋ ๋ฐฉ๋ฒ์ ์ฃผ๋ก ์ฌ์ฉํ๋ค. ์ ์ด๋ ธํ ์ด์ ๊น์ง ์ฌ์ฉํ๋ฉด, ๊ธฐ๋ฅ์ ๋ชจ๋ ์ ๊ณตํ๋ฉฐ ์ฝ๋๋ฅผ ๊น๋ํ๊ฒ ์์ฑํ ์ ์์ด ์ด๋ ๊ฒ ์์ฑํ๋ ๊ฒ์ด ๊ถ์ฅ๋๋ค.
์ด๋ป๊ฒ ์คํ๋ง ์ปจํ ์ด๋์ ํด๋์ค๋ค์ ๋น์ผ๋ก ๋ฑ๋กํ ์ ์์๊น?
1. ์ปดํฌ๋ํธ ์ค์บ๊ณผ ์๋ ์์กด๊ด๊ณ ์ค์
์ฐ์ ์์ ์ฝ๋์์ @Controller์ด๋ ธํ ์ด์ ์ ํตํด MemberController๋ฅผ ์คํ๋ง ์ปจํ ์ด๋์ ๋น์ผ๋ก ๋ฑ๋กํ ์ ์์๋ค.
๋ณดํต @Component์ด๋ ธํ ์ด์ ์ ํตํด ์คํ๋ง ์ปจํ ์ด๋์ ๋น์ ๋ฑ๋กํด ์ฃผ๋๋ฐ ์ด๋ป๊ฒ @Controller ์ด๋ ธํ ์ด์ ์ ํตํด ๋น์ด ๋ฑ๋ก๋ ์ ์์๋ ๊ฑธ๊น?
@Controller ์ด๋ ธํ ์ด์ ์ ๋ค์ด๊ฐ ๋ณด๋ฉด, ์ด๋ ๊ฒ ์ปดํฌ๋ํธ ์ด๋ ธํ ์ด์ ์ด ๋ช ์๋์ด ์๋ค. @Service, @Repository ์ด๋ ธํ ์ด์ ๋ ๋ง์ฐฌ๊ฐ์ง์ด๋ค. ์ด๋ ๊ฒ ์คํ๋ง์ "์ปดํฌ๋ํธ ์ค์บ"์ ํตํด ์๋์ผ๋ก ๊ฐ์ฒด๋ค์ ๋น์ผ๋ก ๋ฑ๋กํ๊ณ , ์์กด๊ด๊ณ๋ฅผ ์ค์ ํ๋ค.
2. ์๋ฐ ์ฝ๋๋ก ์ง์ ์คํ๋ง ๋น ๋ฑ๋กํ๊ธฐ
@Configuration public class SpringConfig { @Bean public MemberService memberService() { return new MemberService(memberRepository()); } @Bean public MemberRepository memberRepository() { return new MemoryMemberRepository(); } }
์ปดํฌ๋ํธ๊ฐ ํฌํจ๋์ด์๋ ์ด๋ ธํ ์ด์ ์ ์ญ์ ํ๊ณ ๋ฑ๋กํด์ฃผ์ด์ผ ํ๋ค.
์คํ๋ง์ ์คํ๋ง ์ปจํ ์ด๋์ ์คํ๋ง ๋น์ ๋ฑ๋กํ ๋, ๊ธฐ๋ณธ์ผ๋ก ์ฑ๊ธํค์ผ๋ก ๋ฑ๋กํ๋ค.
* @Bean๊ณผ @Component์ ์ฐจ์ด์ ??
๊ฐ์๊ธฐ ๊ทธ๋ฌ๋ฉด @Bean๊ณผ @Component๋ ๋ฌด์์ผ๊น? ๋ผ๋ ์๊ฐ์ด ๋ค์๋ค. ๊ทธ๋์ ์ฐพ์๋ณด๋ ๊น์ํ๋์ด ์น์ ํ๊ฒ ๋ต๋ณํด์ฃผ์ จ๋ค.
- @Bean์ ์๋์ผ๋ก ์คํ๋ง ์ปจํ ์ด๋์ ์คํ๋ง ๋น์ ๋ฑ๋กํ๋ ๊ฒ
- @Component๋ ์๋์ผ๋ก ์คํ๋ง ์ปจํ ์ด๋์ ์คํ๋ง ๋น์ ๋ฑ๋กํ๋ ๊ธฐ๋ฅ.
์ถ๊ฐ์ ์ผ๋ก ๋ฐ๋ก ์ ์ฝ๋์ @Configuration๋ ๋ด๋ถ์ @Component๊ฐ ๋ถ์ด์์ด, ์ค์ ์ ๋ณด ์์ฒด๋ ์คํ๋ง ๋น์ผ๋ก ์๋ ๋ฑ๋ก ๋๋ค.
์ฑ๊ธํค ํจํด(Singleton Pattern)์ด๋?
๊ฐ์ฒด์ ์ธ์คํด์ค๊ฐ ์ค์ง 1๊ฐ๋ง ์์ฑ๋๋ ํจํด์ผ๋ก, ์์ฑ์๊ฐ ์ฌ๋ฌ ์ฐจ๋ก ํธ์ถ๋๋๋ผ๋ ์ค์ ๋ก ์์ฑ๋๋ ๊ฐ์ฒด๋ ํ๋์ด๋ฉฐ ์ดํ์ ํธ์ถ๋ ์์ฑ์๋ ์ต์ด์ ์์ฑ์๊ฐ ๊ฐ์ฒด๋ฅผ ๋ฆฌํดํ๋ ๊ฒ. (=๊ณต์ ํ๋ ๊ฒ.) ์๋ฅผ ๋ค์ด OrderService์์ MemberRepository๊ฐ ํ์ํ์ฌ ์์กด ๊ด๊ณ๊ฐ ์ค์ ๋์ด์์ด๋, MemberService์์ ์ฌ์ฉํ๊ณ ์๋ MemberRepository๊ฐ์ฒด๋ฅผ ๋์ด ๊ณต์ ํ์ฌ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค.(์๋ก์ด MemberRepository ๊ฐ์ฒด ์์ฑ ๋๋ ๊ฒ x)
์ฑ๊ธํค ํจํด์ ์ฌ์ฉํ๋ ์ด์
์๋ฒ์ ์ฑ๋ฅ์ ์ฌ๋ฆด ์ ์๋ค. ๋ง์ฝ ์ฑ๊ธํค์ผ๋ก ๋น์ ์์ฑํ์ง ์๊ณ ์์ฒญ ๋ง๋ค ์์ฑํ๋ค๊ณ ๊ฐ์ ํด๋ณด์.
์์ฒญ ํ๊ฐ๋น 5๊ฐ์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์ด๋น 500๊ฐ์ ์์ฒญ์ด ์ฌ ๊ฒฝ์ฐ ๊ฐ์ฒด๋ 2500๊ฐ๋ฅผ ์์ฑํ์ฌ ์๋ฒ์ ์ฑ๋ฅ์ด ์ ํ๋๋ค.
ํ์ง๋ง ์ฑ๊ธํค์ผ๋ก bean์ ์์ฑํ๊ฒ ๋๋ฉด, was์์์์๋ง ์์ฑ์ด ๋๊ณ , ์์ฒญ์ด ๊ณ์ ๋ค์ด์ค๋๋ผ๋ bean์ ๋์ด์ ์์ฑ๋์ง ์๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ์ ๋์ผ ์ ์๋ค.
References
https://mangkyu.tistory.com/150
์ธํ๋ฐ - ์คํ๋ง๊ฐ์(๊น์ํ๋)
'๐ปProgramming > SpringBoot' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ