๐Spring ํต์ฌ ์๋ฆฌ
ํต์ฌ์๋ฆฌ ์๋ฆฌ์ฆ
๊ทธ๋์ Node.js, Nest.js, Django ๋ฑ ์น ํ๋ ์์ํฌ๋ฅผ ๊ณต๋ถํด์์ง๋ง ์คํ๋ง์ด ๊ฐ์ง๋ ์ฐจ๋ณ์ ์ ๋ฌด์์ผ๊น? ์ฐ์ ๋น๊ต์ ์์ ์์ฒด๊ฐ ์๋ชป๋์๋ค. ๋์ดํ ์ ํ๋ ์์ํฌ๋ค์ Spring MVC์ ๋น๊ต๋์ด์ผ ํ ๋ ์๋ค์ด๊ณ ,
์คํ๋ง์ ๋ณธ์ง์
์ข์ ๊ฐ์ฒด ์งํฅ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํ ์ ์๊ฒ ๋์์ฃผ๋ ํ๋ ์์ํฌ
์ด๋ค.
๊ตฌ์ฒด์ ์ธ ์๋ก ๋ฐ๋ก ๋ค์ด๊ฐ๋ณด์.
public class OrderServiceImpl implements OrderService {
// private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
}
์ด ์ฝ๋๋ ๋คํ์ฑ์ ์ด์ฉํด์(๊ทธ๊ฒ๋ ์ ๋ต ํจํด์ ์ฌ์ฉํ์ฌ) switch~case๋ฌธ์ ๋์ฒดํ์๋ค. ์ง๊ธ๊น์ง ์ด์ ๋๋ก๋ ์ถฉ๋ถํ ๋ง์กฑ์ค๋ฌ์ ํ์ง๋ง, ์ ์ฑ ์ด ๋ณํ ๋๋ ์ฃผ์์ฒ๋ฆฌํ ๋ผ์ธ์ฒ๋ผ ๋ถ๋ช ํ ํด๋ผ์ด์ธํธ ์ฝ๋์ ์์ ์ด ์ด๋ฃจ์ด์ง๊ณ ์๋ค. ์ฝ๋๊ฐ ์ถ์ํ(interface)์ ์์กดํ์ง ์๊ณ ๊ตฌ์ฒดํ(RateDiscountPolicy)์ ์์กดํ๊ณ ์๊ธฐ ๋๋ฌธ์ด๋ค. SOLID ์์น ์ค DIP๋ฅผ ์๋ฐํ๊ณ ์๋ค. ๋ํ ๊ธฐ๋ฅ์ ํ์ฅํ๋๋ฐ ๋ณ๊ฒฝ์ด ํ์ํ๋ค. ์ธํธ์ธ OCP ๋ํ ์๋ฐํ๊ณ ์๋ค.
โQuestionโ
Multimode framework๋ฅผ ์ค๊ณํ ๋(TODO: ํ์ดํผ๋งํฌ), ์ถ์ํ ๋ ๋ฒจ์์ ์์กด๊ด๊ณ๊ฐ ๋ชจ๋ ์ ์๋๊ณ RAT๋ณ ๊ตฌํ์ฒด์์๋ ์์ฑ์๋ฅผ ํตํด ๊ตฌ์ฒด์ ์ธ RAT์ ํด๋นํ๋ ๊ตฌํ์ฒด๋ฅผ ๋ฃ์ด์คฌ์๋ค(bridge ํจํด์ด๋ผ๊ณ ์ฃผ์ฅํ์๋ค). ์ค์ ํธ์ถ์ ํ๋ ์์ํฌ์ ์ํด IoC ํํ๋ก ์ถ์ํ ๋ ๋ฒจ์์ ์ด๋ฃจ์ด์ง๋ค. ๋ค๋ง ๊ตฌํ์ฒด๋ RAT specificํ ๊ตฌํ๋ถ๋ฅผ ์์ฑํ ๋, ์์กด๊ด๊ณ์ ์๋ ๋ค๋ฅธ ๊ตฌํ์ฒด๋ฅผ ์ง์ ์ฐธ์กฐํ์ฌ ๋ก์ง์ ์์ฑํ๋ค. ๊ณผ์ฐ ์ธํฐํ์ด์ค๋ง์ ์ฐธ์กฐํ์ฌ ๊ตฌํ์ด ๊ฐ๋ฅํ๊ฐ? ์ด๋ ํ ์ ํ๊ตฐ(LTE, 5G ๋ฑ)์ด ์์๋, ์ ํ๊ตฐ ๋ด์์ ์ธํฐํ์ด์ค๊ฐ ์๋ ์ค์ ๊ตฌํ์ฒด๋ฅผ ์ ๋ฌํ์ฌ ์ฌ์ฉํ๋ ๊ฒ์ ์๋ชป๋ ๊ฒ์ผ๊น?(๋ฌธ์ฅ์ด์ํ๋ค ์ ๋ฆฌํ์. ๊ทผ๋ฐ ์ด๋ ๊ฒ ๋์ค์ ์ ๋ฆฌํ์๊ณ ํ๋ฉด ์์๋๋๋ผ. ๊ทธ๋๊ทธ๋ ์ง์คํด์ ์ ๋ฆฌํด์ผํ๋ค)
๊ทธ๋ ๋ค๋ฉด ์ด๋ป๊ฒ DIP ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ๊ฒ์ธ๊ฐ? (์ฌ์ค ์ด๋ฆ์ ๋ต์ด ์๋ค)
public class OrderServiceImpl implements OrderService {
private DiscountPolicy discountPolicy;
public OrderServiceImpl(DiscountPolicy discountPolicy) {
this.discountPolicy = discountPolicy;
}
}
์๋น์ค๋ฅผ ์์ฑํ๋ ๊ณณ์์ ์ ์ ํ ๊ตฌํ์ฒด๋ฅผ ๋ฃ์ด์ฃผ๊ณ ServiceImpl์ ์ธํฐํ์ด์ค ํํ๋ก ๋ฐ์์ ์ฌ์ฉ์ ํ๋ฉด ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋๋ค. ์ด๋ ๋น๋จ ์คํ๋ง๋ง์ ํด๊ฒฐ๋ฐฉ์์ ์๋๋ฉฐ C++์์๋ ์ด๋ฌํ ๋ฐฉ์์ ํด๊ฒฐ์ ์ํด ์ด์ฌํ ๊ตฌํ์ฒด๋ฅผ ์ ๋ฌํ๊ณ ์ ๋ฌํด์, ์์ ๊ฐ์ ํด๊ฒฐ์ ํ๋ ค๊ณ ๋ ธ๋ ฅํ๋ค. ๊ทธ๋ ๋ค๋ฉด ์คํ๋ง์์๋ ์ด๋ป๊ฒ ์ธ๋ จ๋ ๋ฌธ์ ํด๊ฒฐ์ ๋ณด์ฌ์ค ๊ฒ์ธ๊ฐ?
์ฐ์ ์คํ๋ง์์๋ ๋ฌธ์ ํด๊ฒฐ์ ์ํ์ฌ ๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ๋ฅผ ์ด์ฉํ๋ค. ๊น์ํ๋์ ๋น์ ์ ๋ฐ๋ฅด๋ฉด ๊ฐ์ฒด์งํฅ์ ๋คํ์ฑ์ ๋ก๋ฏธ์ค์ ์ค๋ฆฌ์ฃ์ด๋ผ๋ ๋๋ณธ์ด ์์๋ ๊ฐ ๋ฐฐ์ญ์ ์ด๋ค ๋ฐฐ์ฐ๊ฐ ์บ์คํ ๋๋๋ผ๋ ์ ์ฒด ๊ทน์ ๋ด์ฉ์ ๋ณํจ์ด ์๋ ๊ฒ๊ณผ ๊ฐ์ ๊ฒ์ด๊ณ , ์ฌ๊ธฐ์ ๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ๋ ๋ฐฐ์ญ์ ๋ํ ์บ์คํ ์ ๋ณ๋์ ์ญํ ๋ก ๋ถ๋ฆฌํด์ ์๊ฐํ์๋ ๊ฒ์ด๋ค.
๊ทธ๋์ ๊ณต์ฐ๊ธฐํ์์ ํด๋นํ๋ ์ฝ๋๊ฐ ์ถ๊ฐ๋๋ค.
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
public DiscountPolicy discountPolicy() {
return new FixDiscountPolicy();
}
}
AppConfig๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ค์ ๋์์ ํ์ํ ๊ตฌํ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค. ์ด๋ SOLID ์์น ์ค SRP์๋ ๊ด๊ณ๊ฐ ์๋ค. ๋น์ง๋์ค ๋ก์ง์ฒ๋ฆฌ์ ์์กด๊ด๊ณ ์ค์ ์ด๋ผ๋ ๋ ๊ฐ์ ์ฑ ์์ ๋ ๊ฐ์ ํด๋์ค๋ก ๋ถ๋ฆฌํ ๊ฒ์ด๋ค.
โQuestionโ
ํจ์๋ช ์ ๊ฐ์ฒด๋ช ์ผ๋ก ์ฐ๋ ๊ฒ์ด ๋ง๋๊ฒ์ธ๊ฐ?
๋ํ ๊ณต์ฐ๊ธฐํ์๊ฐ ์์ฑํ ๊ฐ์ฒด๋ฅผ ์์ฑ์๋ฅผ ํตํด์ ์ ๋ ฅ(์ฃผ์ )๋ฐ๋๋ค. ์ด๋ฅผ ํตํด์ ์๋น์ค ๊ตฌํ์ฒด๋ ๊ตฌ์ฒด์ ์ธ ์ ์ฑ ์ ๋ชจ๋ฅด๊ณ ๋ ์๋ํ ์ ์๊ฒ ๋๋ค.
public static void main(String[] args) {
AppConfig appConfig = new AppConfig();
MemberService memberService = appConfig.memberService();
Member member = new Member(1L, "memberA", Grade.VIP);
memberService.join(member);
}
ํด๋ผ์ด์ธํธ(MemberServiceImpl) ์ ์ฅ์์ ์์กด์ฑ์ด ์ธ๋ถ์์ โ์ฃผ์ โ๋๋ค๊ณ ํ์ฌ, ์ด๋ฅผ ์์กด์ฑ ์ฃผ์ (Dependancy Injection)์ด๋ผ๊ณ ํ๋ค.
๋น์ทํ ๊ฐ๋ ์ผ๋ก DL(Dependancy Lookup)์ด ์๋ค. ์์กด์ฑ์ ์ฃผ์ ๋ฐ์ง ์๊ณ ์ฐพ๊ธฐ๋ง ํ๋ ๊ฐ๋ ์ธ๋ฐ, ๋ค์ ํ๋กํ ํ์ ๋น์์ ์๊ฐ๋ ๊ฒ์ด๋ค.
TODO : 38 PAGE ๊ทธ๋ฆผ ๊ทธ๋ ค๋ฃ๊ธฐ
AppConfig์ ๋ฑ์ฅ์ผ๋ก ์ ํ๋ฆฌ์ผ์ด์ ์ด ํฌ๊ฒ ์ฌ์ฉ ์์ญ๊ณผ, ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๊ตฌ์ฑ(Configuration)ํ๋ ์์ญ์ผ๋ก ๋ถ๋ฆฌ๋์๋ค. ์ด์ ์ฌ์ฌ ์คํ๋ง์ ์ธํ ํ๋๊ฒ ๋๋ฌด ๋ณต์กํด๋ผ๊ณ ์ธ๋ป์ธ๋ป ๋ค์๋ ์ด์ผ๊ธฐ๊ฐ ๊ธฐ์ต๋๊ธฐ ์์ํ๋ค. ์ ์ ์ ๋ ธํ ์ด์ ๋ ์ฌ์ฉํ๊ณ ์ต๋ํ ํธํด์ง๋ ค๊ณ ๋ ธ๋ ฅํ์ง๋ง ๋ณธ์ง์ ์์กด๊ด๊ณ๊ฐ ์ค์ ์์ ์ด๋ฏธ ์ ์๋๊ธฐ ๋๋ฌธ์ด๋ค.
๊ทธ๋ฐ๋ฐ ์์๊ฐํด๋ณด๋ฉด ์์ง ์คํ๋ง์ ์ฌ์ฉํ์ง๋ ์์๋ค. ์คํ๋ง์ ์ฃผ์๊ธฐ๋ฅ์ธ DI๋ฅผ java๋ก ๊ตฌํํ์๋ฟ์ด๋ค. ์ด์ ๋ถํฐ ์ง์ง๋ก ์คํ๋ง์ ์ฌ์ฉํด๋ณด๋๋ก ํ์.
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(
memberRepository(),
discountPolicy());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
public DiscountPolicy discountPolicy() {
return new RateDiscountPolicy();
}
}
๊ธฐ์กด AppConfig์ ์ ๋ ธํ ์ด์ (@๊ฐ ๋ถ์ ํค์๋)์ ์ถ๊ฐํ์๋ค. ์ ๋ ธํ ์ด์ ์ C++์์ ํ๋ ๊ฒ์ฒ๋ผ ๋ถ๊ฐ์ ์ธ ์ ๋ณด๋ฅผ ์ ๋ฌํด์ ๋ฉํ ํ๋ก๊ทธ๋๋ฐ์ ๊ฐ๋ฅํ๊ฒ ํด์ค๋ค. ์ ๋ ธํ ์ด์ ์ ๋ํ ๊ตฌ์ฒด์ ์ธ ๋ฌธ๋ฒ๊ณผ ๊ตฌํ์ ๋ค๋ฅธ ๊ธ์ ํตํด ์ ๋ฆฌํ๋ ค ํ๋ค.
K๊ต์์ ๊ฐ์ฒด์งํฅ ์ด์ผ๊ธฐ ์ฑ ์ ๋ณด๋ฉด ๊ฐ์ฒด๋ฅผ ์ ์ํ๊ธฐ ์ํ ๋ค๊ฐ์ง ์์๊ฐ ๋์ค๋๋ฐ, ๊ทธ ์ค ์์ํ ๊ฐ๋ ์ธ ๊ณต๋ฆฌ(axiom)์ด ์๋ค. ์๊ตฌ์ฌํญ์ ๋ํ ๋ช ์๋ฅผ ๋งํ๋๋ฐ ์ฑ ์์๋ ์ด๋ฅผ ๊ตฌํํ ๋ฌธ๋ฒ์ ์ธ ์์๊ฐ ์์ผ๋ฏ๋ก ์๊ณ ๋ฆฌ์ฆ ๊ตฌํ์ ์ด๋ฅผ ์ง์ ๊ตฌํํด์ผ ํ๋ค๊ณ ๋์์์ง๋ง, ์ ๋ ธํ ์ด์ ์ด ์ด๋ฐ ๋ถ๋ถ์ ํด๊ฒฐํด์ฃผ๊ณ ์๋ค.
@Configuration์ ์ํด ๊ณต์ฐ๊ธฐํ์ ์ฃผ์ฒด๋ Spring Container๊ฐ ๋๊ณ , ๊ณต์ฐ์ ๊ฐ์ฒด๋ @Bean์ ์ํด ์ ์๋๋ค.
๋ํ AppConfig๋ฅผ ์ฌ์ฉํ๋ ์ฝ๋๋ ์๋์ฒ๋ผ ๋ณ๊ฒฝ๋์๋ค.
public static void main(String[] args) {
// AppConfig appConfig = new AppConfig();
// MemberService memberService = appConfig.memberService();
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
}
โQuestionโ
getBean()์ ๋ํด ๊ณ ๋ฏผํด๋ณด์. ๋ง์น ์ ๋ํฐ ๊ฒ์์์ง์์ getGameObject()๋ก ๋ฌธ์์ด์ ํตํด ๋ค๋ฅธ ๊ฒ์์ค๋ธ์ ํธ๋ฅผ ์ป์ด์ค๋ ๊ฒ๊ณผ ๋น์ทํ๋ค. ๋ฌผ๋ก ์คํ๋ง์ด ์ค๋ฆฌ์ง๋์ด๊ฒ ์ง๋ง. ๊ณผ์ฐ ์ด ๋ฐฉ์์ ํ๋ฅญํ ๊ฒ์ธ๊ฐ? ์ด๋ค Bean์ด๋ ๋ฌธ์์ด์ด๋ ํ์ ์ ํตํด ์ป์ด์ฌ ์ ์์ด์ผ ํ๋ ๊ฒ์ธ๊ฐ? Bean ์ ์ฅ์์ ์์ ์ ๊ฐ์ ธ๊ฐ ์ ์๋ ๊ถํ์ ํน์ ๊ฐ์ฒด๋ก ์ ํํด์ผํ์ง ์์๊น?๋์ค์ ๋์ฌ ๋ด์ฉ์ผ๋ก ์์ฑ์๋ก ํ์ํ ๊ฐ์ฒด๋ฅผ ์ธ์๋ก ๋ฐ์ผ๋ฉด @Autowired๋ฅผ ํตํด ์คํ๋ง์ด ๋ฃ์ด์ฃผ๋ ๋ด์ฉ์ด ์๋ค. ์์ฑ์ ์ธ์๋ ์๊ตฌ์ฌํญ์ด๋ผ๊ณ ํ ๋, ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ฌ์ง๊ฐ ์์๊น?
์ค์ ์ ๋ฐฉ์์ XML์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ๊ณผ ์ ๋ ธํ ์ด์ (AnnotationConfigApplicationContext)์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด ์๋๋ฐ, ํ์๊ฐ ํ์ฌ๋ ์ ๋์ ์ธ ๋์ธ์ด๋ฏ๋ก ์์ผ๋ก ์ด ๋ฐฉ์์ผ๋ก ์ฌ์ฉํ๋๋ก ํ๋ค.
โXML ๋ฐฉ์โ
XML ๋ฐฉ์์ ์๋์ ๊ฐ์ด GenericXmlApplicationContext๋ฅผ ์ฌ์ฉํ๋ค. ์ด ๋ฐฉ์์ ์ปดํ์ผ์์ด๋ ์์กด๊ด๊ณ๋ฅผ ์์ ํ ์ ์๋ ์์ฃผ ํฐ ์ฅ์ ์ด ์์ง๋ง ์๋์์ ๋ณด๋ฏ ์์ฑ์ด ๊ท์ฐฎ๋ค. ๋ํ working code๋ฅผ ์ค์์ํ๋ ์ ์์ผ ๋ฌธํ ์์์ ์ด ๋ฐฉ์์ ์ ๋ ธํ ์ด์ ์๊ฒ ๋ฐ๋ ค๋ฒ๋ฆฌ๊ณ ๋ง์๋ค. ์์ง ์ฌ์ฉํ๋ ๋ ๊ฑฐ์๊ฐ ์์ ์ ์์ผ๋ ์์๋ ๋์.
ApplicationContext ac = new GenericXmlApplicationContext("appConfig.xml");
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://
www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="memberService" class="hello.core.member.MemberServiceImpl">
<constructor-arg name="memberRepository" ref="memberRepository" />
</bean>
</beans>
์ด์ ๋ค์๊ธ(TODO:LINK)์์ ์คํ๋ง ์ปจํ ์ด๋์ Bean์ ๋ด๋ถ๊ตฌ์กฐ ๋ฐ ์ฌ์ฉ๋ฒ์ ๋ํด ์์ธํ ์ตํ๋ณด๋๋ก ํ์.