2021. 10. 3. 08:00ใBack-End ์์ ์ค/Spring Framework
์๋ ํ์ธ์? ์ฃผ๋ํ๋ ์ ๋๋ค.
์ค๋์ Spring์ ์คํ๋ง ์ปจํ ์ด๋์ ์คํ๋ง ๋น์ ๋ํด์ ๊ณต๋ถ ํด ๋ณด๋๋ก ํ๋ ๊ฒ์ด์์.
์ด ๋ด์ฉ์ ์ธํ๋ฐ - ๊น์ํ ๊ฐ์ฌ๋์ ์คํ๋ง ํต์ฌ ์๋ฆฌ๋ฅผ ๊ณต๋ถํ๋ฉด์ ์ ๋ฆฌ ํ์์ต๋๋ค.
๐ ๋ชฉ์ฐจ
01. [Spring] ์คํ๋ง ํต์ฌ ์๋ฆฌ
02. [Spring] ์ข์ ๊ฐ์ฒด ์งํฅ ์ค๊ณ์ 5๊ฐ์ง ์์น (SOLID)
03. [Spring] ๊ฐ์ฒด ์งํฅ ์ค๊ณ์ ์คํ๋ง
04. [Spring] OCP์ DIP ๊ณ ๋ คํ๊ธฐ
05. [Spring] ๊ฐ์ฒด ์งํฅ ์๋ฆฌ ์ ์ฉ - ์๋ก์ด ํ ์ธ ์ ์ฑ
๊ฐ๋ฐ
06. [Spring] AppConfig ๋ฆฌํฉํฐ๋ง
07. [Spring] Ioc, DI Container
08. [Spring] ์คํ๋ง ์ปจํ
์ด๋ ์์ฑ
09. [Spring] ์ฑ๊ธํค ์ปจํ
์ด๋
10. [Spring] Component Scan And Auto wired Start
11. [Spring] ์์กด๊ด๊ณ ์ฃผ์
๋ฐฉ๋ฒ
12. [Spring] Bean Life Cycle Call Back
13. [Spring] Bean Scope
๐ Spring Container Create
๋จผ์ ์คํ๋ง ์ปจํ ์ด๋๊ฐ ์์ฑ๋๋ ๊ณผ์ ๋ถํฐ ์์๋ด์ผ ํ๋ ๊ฒ์ด์์.
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
ApplicationContext๋ฅผ Spring Container๋ผ๊ณ ํ๋ ๊ฒ์ด์์. ๋ํ ์ด๊ฒ์ Interface๋๋๋ค!
Spring Container๋ XML ๊ธฐ๋ฐ์ผ๋ก ๋ง๋ค์๋ ์๊ณ , Annotaion ๊ธฐ๋ฐ์ Java ์ค์ Class๋ก ๋ง๋ค ์๋ ์๋ ๊ฒ์ด์์.
์ด ์ ์ AppConfig.java๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ์์ด ๋ฐ๋ก Annotaion ๊ธฐ๋ฐ์ Java ์ค์ Class๋ก Spring Container๋ฅผ ๋ง๋ ๊ฒ์ด์์.
Java ์ค์ Class๋ฅผ ๊ธฐ๋ฐ์ผ๋ก Spring Container(ApplicationContext)๋ฅผ ๋ง๋ค์ด ๋ณผ๊น์?
- new AnnotaionConfigApplicationContext(AppConfig.class);
- ์ด Class๋ ApplicationContext Interface์ ๊ตฌํ์ฒด
์ฐธ๊ณ : ์ ํํ๋ Spring Container๋ฅผ ๋ถ๋ฅผ ๋, BeanFactory, ApplicationContext๋ก ๊ตฌ๋ถํด์ ์ด์ผ๊ธฐ ํ๋ค.
BeanFactory๋ฅผ ์ง์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ ๊ฑฐ์ ์์ผ๋ฏ๋ก, ์ผ๋ฐ์ ์ผ๋ก ApplicationContext๋ฅผ Spring Container๋ผ๊ณ ํ๋ค.
๐Spring Container ์์ฑ ๊ณผ์
๐ RateDiscountPolicy ์ถ๊ฐ
new AnnotaionConfigApplicationContext(AppConfig.class);
์์ ๊ฐ์ด Spring Container๋ฅผ ์์ฑํ ๋ ๊ตฌ์ฑ ์ ๋ณด(์ธ์๊ฐ์ ๋ค์ด๊ฐ๋ ๊ตฌ์ฑ ์ ๋ณด๋ฅผ ๋ด์ Class)๋ฅผ ์ง์ ํด์ฃผ์ด์ผ ํ๋ ๊ฒ์ด์์.
์ฌ๊ธฐ์๋ AppConfig.class๋ก ์ฌ์ฉํ์์ฃ .
๐ Spring Bean ๋ฑ๋ก
์คํ๋ง ์ปจํ ์ด๋๋ ํ๋ผ๋ฏธํฐ๋ก ๋์ด ์จ ์ค์ ํด๋์ค ์ ๋ณด๋ฅผ ์ด์ฉํ์ฌ ์คํ๋ง ๋น์ ๋ฑ๋กํ๋ ๊ฒ์ด์์.
์ฌ๊ธฐ์ ๋น ์ด๋ฆ์ Method์ ์ด๋ฆ์ ์ฌ์ฉํ๊ฒ ๋๋ฉฐ, ์ง์ ๋ถ์ฌํ ์๋ ์๋ ๊ฒ์ด์์. ๋ฐ๋ก ์๋ ์ฝ๋์ฒ๋ผ์!
@Bean(name = "BeanName์
๋ ฅ")
ํ์ง๋ง, ์กฐ์ฌํด์ผ ํ๋ ๊ฒ์ด ์๋ ๊ฒ์ด์์. Bean ์ด๋ฆ์ ํญ์ ๋ค๋ฅธ ์ด๋ฆ์ ๋ถ์ฌํด์ผ ํ๋ ๊ฒ์ด์์.
๊ฐ์ ์ด๋ฆ์ ๋ถ์ฌํ๋ฉด Spring Container๋ ๋ค๋ฅธ ๋น์ ๋ฌด์ํด ๋ฒ๋ฆฌ๊ฑฐ๋, ๊ธฐ์กด ๋น์ ๋ฎ์ด์ฐ๊ธฐ ํด ๋ฒ๋ฆฌ๊ฑฐ๋, ์ค์ ์ ๋ฐ๋ผ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ ๊ฒ์ด์์.
๐ Spring Bean ์์กด๊ด๊ณ ์ค์ - ์ค๋น
๐ Spring Bean ์์กด๊ด๊ณ ์ค์ - ์๋ฃ
์คํ๋ง ์ปจํ ์ด๋๋ ์ค์ ์ ๋ณด๋ฅผ ์ฐธ๊ณ ํด์ ์์กด๊ด๊ณ๋ฅผ ์ฃผ์ (DI)ํ๋ ๊ฒ์ด์์.
๋จ์ํ Java์ Method๋ฅผ ํธ์ถํ๋ ๊ฒ ๊ฐ์ด ๋ณด์ด์ง๋ง, ์ฐจ์ด๊ฐ ์๋ ๊ฒ์ด์์.
์ฐธ๊ณ ๋ก ์คํ๋ง ๋น์ ์์ฑํ๊ณ , ์์กด๊ด๊ณ๋ฅผ ์ฃผ์ ํ๋ ๋จ๊ณ๊ฐ ๋๋ ์ ธ ์๋ ๊ฒ์ด์์. ๊ทธ๋ฐ๋ฐ, ์ด๋ ๊ฒ Java ์ฝ๋๋ก ์คํ๋ง ๋น์ ๋ฑ๋กํ๋ฉด ์์ฑ์๋ฅผ ํธ์ถํ๋ฉด์ ์์กด๊ด๊ณ ์ฃผ์ ๋ ํ๋ฒ์ ์ฒ๋ฆฌ๋์ด ๋ฒ๋ฆฌ๋ ๊ฒ์ด์์. ์ด๋ฒ ๊ณต๋ถ์์๋ ์ดํด๋ฅผ ๋๊ธฐ ์ํด ๊ฐ๋ ์ ์ผ๋ก ๋๋ ์ ์์ฑ ํด ๋ณผ๊ฒ์!
์ ๋ฆฌํ์๋ฉด
์คํ๋ง ์ปจํ ์ด๋๋ฅผ ์์ฑํ๊ณ , ์ค์ (๊ตฌ์ฑ) ์ ๋ณด๋ฅผ ์ฐธ๊ณ ํด์ ์คํ๋ง ๋น๋ ๋ฑ๋กํ๊ณ , ์์กด๊ด๊ณ๋ ์ค์ ํ ๊ฒ์ด์์.
์ด์ ํ๋ฒ Data๋ฅผ ์กฐํ ํด ๋ด์ ์ฐ๋ฆฌ!
๐ ์ปจํ ์ด๋์ ๋ฑ๋ก๋ ๋ชจ๋ ๋น ์กฐํ
package hello.core.beanfind;
import hello.core.AppConfig;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class ApplicationContextInfoTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test @DisplayName("๋ชจ๋ Bean ์ถ๋ ฅํ๊ธฐ")
void findAllBean() {
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name = " + beanDefinitionName + "\n object = " + bean);
System.out.println("----------------------------------------------------------------");
}
}
@Test @DisplayName("Application Bean ์ถ๋ ฅํ๊ธฐ")
void findApplicationBean() {
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName); // getBeanDefinition ์ด๊ฒ์ Bean์ ๋ํ Meta Data ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
// ROLE_INFRASTRUCTOR๋ ์คํ๋ง ๋ด๋ถ์์ ์ฌ์ฉํ๋ Bean์ ๋ํด ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) { // getRole Method์์ ROL_AAPLICATON์ Spring์ด ์ฌ์ ์ ๋ฑ๋กํ Bean์ด ์๋ ์ฌ์ฉ์๊ฐ ์์ฑํ Bean ํน์ ์ธ๋ถ Library ๋ผ๋ ๋ป
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name = " + beanDefinitionName + "\n object = " + bean);
System.out.println("----------------------------------------------------------------");
}
}
}
} // Class ๋
- ๋ชจ๋ ๋น ์ถ๋ ฅ
- ์คํ ์ Spring์ ๋ฑ๋ก๋ ๋ชจ๋ ๋น ์ ๋ณด ์ถ๋ ฅ
- AnnotationConfigApplicationContext.getBeanDefinitionNames() : ์คํ๋ง์ ๋ฑ๋ก๋ ๋ชจ๋ ๋น ์ด๋ฆ ์กฐํ ์ ์ฌ์ฉ
- AnnotationConfigApplicationContext.getBean() : ๋น ์ด๋ฆ์ผ๋ก ๋น ๊ฐ์ฒด(์ธ์คํด์ค) ์กฐํ ์ ์ฌ์ฉ
- Application Bean Output
- ์คํ๋ง ๋ด๋ถ์์ ์ฌ์ฉํ๋ ๋น์ ์ ์ธํ๊ณ , ์ฐ๋ฆฌ๊ฐ ๋ง๋ ๋น๋ง ์ถ๋ ฅํ๋ ๋ฐฉ๋ฒ
- ์คํ๋ง ๋ด๋ถ์์ ์ฌ์ฉํ๋ ๋น์ getRole()์ ์ฌ์ฉํ์ฌ ๊ตฌ๋ถ ๊ฐ๋ฅ
- ROLE_APPLICATION : ์ผ๋ฐ์ ์ผ๋ก ๊ฐ๋ฐ์๊ฐ ์ ์ํ ๋น
- ROLE_INFRASTRUCTURE : ์คํ๋ง ๋ด๋ถ์์ ์ฌ์ฉํ๋ ๋น
๐ Spring Bean ์กฐํ - ๊ธฐ๋ณธ
์คํ๋ง ์ปจํ ์ด๋์์ ์คํ๋ง ๋น์ ์ฐพ๋ ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ์ ๋ฌด์์ผ๊น์?
- AnnotationConfigApplicationContext.getBean(BeanName, BeanType)
- AnnotationConfigApplicationContext.getBean(BeanType)
- ์กฐํ ๋์ ์คํ๋ง ๋น์ด ์์ ๊ฒฝ์ฐ ์์ธ ๋ฐ์
- NoSuchBeanDefinitionException : No bean named '~~~~' available
package hello.core.beanfind;
import hello.core.AppConfig;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class ApplicationContextBasicFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test @DisplayName("Bean Name์ผ๋ก ์กฐํ")
void findBeanName() {
MemberService memberService = ac.getBean("memberService", MemberService.class);
Assertions.assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
} // findBeanName() ๋
@Test @DisplayName("์ด๋ฆ ์์ด ํ์
์ผ๋ก๋ง ์กฐํ")
void findBeanByType() {
MemberService memberService = ac.getBean(MemberService.class);
Assertions.assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
} // findBeanByType() ๋
@Test @DisplayName("๊ตฌ์ฒด ํ์
์ผ๋ก ์กฐํ")
void findBeanName1() { // ์ด๋ ๊ฒ ๊ตฌ์ฒดํ๋ฅผ ํตํด ์กฐํ๋ฅผ ํ๋ ๊ฒ์ ์ข์ง ์๋ค. ์๋ํ๋ฉด? ์ถ์ํ์ ์์กดํด์ผ ํ๋๋ฐ, ๊ตฌ์ฒดํ์ ์์กดํ๊ธฐ ๋๋ฌธ
MemberService memberService = ac.getBean("memberService", MemberServiceImpl.class);
Assertions.assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
} // findBeanByType() ๋
@Test @DisplayName("๋น ์ด๋ฆ์ผ๋ก ์กฐํ๊ฐ ๋์ง ์์ ๋")
void findBeanByNameX() { // Test๋ฅผ ๋ง๋ค ๋๋ ์คํจ์ ๋ํ ๊ฒ๋ ๋ง๋ค์ด์ผ ํ๋ค.
// ac.getBean("xxxx", MemberService.class); MemberService์ "xxxx"๋ผ๋ ์ด๋ฆ์ผ๋ก ๋ Bean์ด ์๊ธฐ ๋๋ฌธ์ NoSuchBeanDefinitionException Exception์ด ๋ฐ ๊ฒ์ด๋ค.
org.junit.jupiter.api.Assertions.assertThrows(NoSuchBeanDefinitionException.class,
() -> ac.getBean("xxxx", MemberService.class)); // ์ค๋ฅธ์ชฝ์ ์ธ์๊ฐ์ด ์คํ๋๋ฉด ์ผ์ชฝ ์ธ์๊ฐ Exception์ด ํฐ์ ธ์ผ Test ์ ์์ด ๋์จ๋ค.
} // findBeanByNameX() ๋
} // Class ๋
์ฐธ๊ณ ๋ก ๊ตฌ์ฒด Type์ผ๋ก ์กฐํํ๋ฉด ๋๋ค ์๋๋ค? ์ ๋๋ค! ์ ์๋๋ค? ์ญํ ๊ณผ ๊ตฌํ์ ๋๋ ์ผ ํ๊ณ , DIP, OCS ์๋ฐ์ด๋ค!
๊ทธ๋ฌ๋ฏ๋ก, ๋ณ๊ฒฝ ์ ์ ์ฐ์ฑ์ด ๋จ์ด์ง๊ฒ ๋๊ธฐ ๋๋ฌธ์ ์ฃผ์ ํด์ผ ํ๋ ๊ฒ์ด์์!
๐ Spring Bean ์กฐํ - ๋์ผํ ํ์ ์ด ๋ ์ด์์ผ ๋
๋ง์ฝ ํ์
์ผ๋ก ์กฐํํ ๋, ๊ฐ์ ํ์
์ ์คํ๋ง ๋น์ด ๋ ์ด์์ด๋ฉด ์์ธ๊ฐ ๋ฐ์ํ๋ ๊ฒ์ด์์. ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์๋ ๋น ์ด๋ฆ์ ์ง์ ํ๋ ๋ฐฉ๋ฒ์ด ์์๊ฒ์ด์์.
AnnotationConfigApplicationContext.getBeanOfType()์ ์ฌ์ฉํ๊ฒ ๋๋ฉด ํด๋น ํ์
์ ๋ชจ๋ ๋น์ ์กฐํํ ์ ์๋ต๋๋ค!
package hello.core.beanfind;
import hello.core.member.MemberRepository;
import hello.core.member.MemoryMemberRepository;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
public class ApplicationContextBeanFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SameBeanConfig.class);
@Configuration
static class SameBeanConfig { // Bean ์ด๋ฆ์ด ๋ค๋ฅด๊ณ , ๊ฐ์ฒด ํ์
(์ธ์คํด์ค ํ์
)์ด ๊ฐ๊ฒ ํ ์ ์๋ค.
@Bean
public MemberRepository memberRepository1() {
return new MemoryMemberRepository();
} // memberRepository1() ๋
@Bean
public MemberRepository memberRepository2() {
return new MemoryMemberRepository();
} // memberRepository2() ๋
} // SameBeanConfig Class ๋
@Test @DisplayName("ํ์
์ผ๋ก ์กฐํ ์ ๊ฐ์ ํ์
์ด ๋ ์ด์ ์์ผ๋ฉด, ์ค๋ณต ์ค๋ฅ ๋ฐ์")
void findBeanByTypeDuplicate() {
MemberRepository bean = ac.getBean(MemberRepository.class);
Assertions.assertThrows(NoUniqueBeanDefinitionException.class, () -> ac.getBean(MemberRepository.class));
} // findBeanByTypeDuplicate() ๋
@Test @DisplayName("ํ์
์ผ๋ก ์กฐํ ์ ๊ฐ์ ํ์
์ด ๋ ์ด์ ์์ผ๋ฉด, Bean ์ด๋ฆ ์ง์ ์ ํด๊ฒฐ")
void findBeanByName() {
MemberRepository memberRepository = ac.getBean("memberRepository1", MemberRepository.class);
org.assertj.core.api.Assertions.assertThat(memberRepository).isInstanceOf(MemberRepository.class);
} // findBeanByName() ๋
@Test @DisplayName("ํน์ ํ์
์ ๋ชจ๋ ์กฐํํ๊ธฐ")
void findAllBeanByType() {
Map<String, MemberRepository> beanOfType = ac.getBeansOfType(MemberRepository.class);
for (String key : beanOfType.keySet()) {
System.out.println("key = " + key + "\n Value = " + beanOfType.get(key));
}
System.out.println("beanOfType = " + beanOfType);
org.assertj.core.api.Assertions.assertThat(beanOfType.size()).isEqualTo(2);
} // findAllBeanByType() ๋
} // Class ๋
๐ Spring Bean ์กฐํ - ์์ ๊ด๊ณ
๋ถ๋ชจ ํ์ ์ผ๋ก ์กฐํํ๋ฉด ์์ ํ์ ๋ ํจ๊ป ์กฐํ๋๋ ๊ฒ์ด์์.
๋ฐ๋ผ์ ๋ชจ๋ ์๋ฐ ๊ฐ์ฒด์ ์ต๊ณ ๋ถ๋ชจ ์๋ด๊ณผ ํ์ ๊ฒฉ์ธ Java์ Object ํ์ ์ผ๋ก ์กฐํํ๋ฉด ๋ชจ๋ ์คํ๋ง ๋น๋ ์กฐํ๊ฐ ๋๋ ๊ฒ์ด์์.
package hello.core.beanfind;
import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.discount.RateDiscountPolicy;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
public class ApplicationContextExtendsFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
@Configuration
static class TestConfig {
@Bean
public DiscountPolicy rateDiscountPolicy() {
return new RateDiscountPolicy();
} // rateDiscountPolicy() ๋
@Bean
public DiscountPolicy fixDiscountPolicy() {
return new FixDiscountPolicy();
} // fixDiscountPolicy() ๋
} // TestConfig Class ๋
@Test
@DisplayName("๋ถ๋ชจ ํ์
์ผ๋ก ์กฐํ ์ ์์์ด ๋ ์ด์ ์์ผ๋ฉด, ์ค๋ณต ์ค๋ฅ ๋ฐ์")
void findBeanByParentTypeDuplicate() {
// DiscountPolicy bean = ac.getBean(DiscountPolicy.class);
Assertions.assertThrows(NoUniqueBeanDefinitionException.class, () -> ac.getBean(DiscountPolicy.class));
} // findBeanByParentTypeDuplicate() ๋
@Test
@DisplayName("๋ถ๋ชจ ํ์
์กฐํ ์ ์์์ด ๋ ์ด์ ์์ผ๋ฉด, Bean ์ด๋ฆ์ผ๋ก ์กฐํํ๋ฉด ๋๋ค.")
void findBeanByParentTypeBeanName() {
DiscountPolicy bean = ac.getBean("rateDiscountPolicy", DiscountPolicy.class);
org.assertj.core.api.Assertions.assertThat(bean).isInstanceOf(RateDiscountPolicy.class);
} // findBeanByParentTypeBeanName() ๋
@Test
@DisplayName("๋ถ๋ชจ ํ์
์กฐํ ์ ์์์ด ๋ ์ด์ ์์ผ๋ฉด, ํน์ ํ์ ํ์
์ผ๋ก ์กฐํ ๊ฐ๋ฅ(๊ตฌํ์ฒด๋ฅผ ์์กดํ๊ธฐ ๋๋ฌธ์ ์ข์ง ์์ ๋ฐฉ๋ฒ)")
void findBeanBySubType() {
RateDiscountPolicy bean = ac.getBean(RateDiscountPolicy.class);
org.assertj.core.api.Assertions.assertThat(bean).isInstanceOf(RateDiscountPolicy.class);
} // findBeanBySubType() ๋
@Test
@DisplayName("๋ถ๋ชจ ํ์
์ผ๋ก ์ ๋ถ ์กฐํ")
void findAllBeanByPrentType() {
Map<String, DiscountPolicy> beansOfType = ac.getBeansOfType(DiscountPolicy.class);
org.assertj.core.api.Assertions.assertThat(beansOfType.size()).isEqualTo(2);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + "\n Value = " + beansOfType.get(key));
} // for๋ฌธ ๋
} // findAllBeanByPrentType() ๋
@Test
@DisplayName("์๋ฐ์ ์๋ด Object ํ์
์ผ๋ก ์ ๋ถ ์กฐํ")
void findAllBeanByObjectType() {
Map<String, Object> beansOfType = ac.getBeansOfType(Object.class);
org.assertj.core.api.Assertions.assertThat(beansOfType.size()).isEqualTo(16);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + "\n value = " + beansOfType.get(key));
} // for๋ฌธ ๋
} // findAllBeanByObjectType() ๋
} // Class ๋
๐ BeanFactory์ ApplicationContext
BeanFactory
- ์คํ๋ง ์ปจํ ์ด๋์ ์ต์์ ์ธํฐํ์ด์ค
- ์คํ๋ง ๋น์ ๊ด๋ฆฌํ๊ณ , ์กฐํํ๋ ์ญํ
- getBean() ์ ๊ณต
- ์ ์จ ํ์ธํ๋ ๋ชจ๋ ๊ธฐ๋ฅ์ BeanFactory๊ฐ ์ ๊ณตํ๋ ๊ธฐ๋ฅ
ApplicationContext
- BeanFactory ๊ธฐ๋ฅ์ ๋ชจ๋ ์์ ๋ฐ์ ์ ๊ณต
- ๋น์ ๊ด๋ฆฌํ๊ณ ๊ฒ์ํ๋ ๊ธฐ๋ฅ์ BeanFactory๊ฐ ์ ๊ณต
- Application ๊ฐ๋ฐ ์ ๋น์ ๊ด๋ฆฌํ๊ณ , ์กฐํํ๋ ๊ธฐ๋ฅ์ ๋ฌผ๋ก ์ ๋ง์ ๋ถ๊ฐ ๊ธฐ๋ฅ ํ์ํ๋ฐ, ์ด๋ฅผ ์ ๊ณต
- MessageSource
- ๋ฉ์์ง์์ค๋ฅผ ํ์ฉํ ๊ตญ์ ํ ๊ธฐ๋ฅ : ์๋ฅผ ๋ค์ด ํ๊ตญ์์ ์ ์ํ๋ฉด ํ๊ตญ์ด๋ก ๋ณด์ด๊ฒ ํ๊ณ , ๋ค๋ฅธ ์ธ์ด๊ถ์์ ์ ์ํ๋ฉด ๊ทธ ๋๋ผ์ ์ธ์ด๋ก ์ถ๋ ฅ
- EnvironmentCapable
- ํ๊ฒฝ ๋ณ์ : ๊ฐ์ธ PC์์ ํน์ ๊ฐ๋ฐ ์๋ฒ์์ ์ด์ ์๋ฒ์์ ํ๋ ์ผ์ด ๋ชจ๋ ๋ค๋ฅด ๋ฏ ์ด๋ฅผ ๊ตฌ๋ถํด์ ์ฒ๋ฆฌ
- ApplicationEventPublisher
- ์ ํ๋ฆฌ์ผ์ด์ ์ด๋ฒคํธ : ์ด๋ฒคํธ๋ฅผ ๋ฐํํ๊ณ , ๊ตฌ๋ ํ๋ ๋ชจ๋ธ์ ํธ๋ฆฌํ๊ฒ ์ง์
- ResourceLoader
- ํธ๋ฆฌํ ์์ ์กฐํ : File, Class Path, Remote(์ธ๋ถ) ๋ฑ์์ ์์์ ํธ๋ฆฌํ๊ฒ ์กฐํํ ์ ์๋๋ก ์ง์
์ ๋ฆฌํ์๋ฉด
- ApplicationContext๋ BeanFactory์ ๊ธฐ๋ฅ ์์
- ApplicationContext๋ ๋น ๊ด๋ฆฌ ๊ธฐ๋ฅ๊ณผ ๋๋ถ์ด ํธ๋ฆฌํ ๋ถ๊ฐ ๊ธฐ๋ฅ ์ ๊ณต
- BeanFactory๋ฅผ ์ง์ ์ฌ์ฉํ ์ผ์ ๊ฑฐ์ ์๊ณ , ๋ถ๊ฐ ๊ธฐ๋ฅ์ด ํฌํจ๋ ApplicationContext ์ฌ์ฉ
- BeanFactory๋ ApplicationContext๊ฐ ๋ฐ๋ก ์คํ๋ง ์ปจํ ์ด๋
๐๋ค์ํ ์ค์ ํ์ ์ง์ - Java Code, XML
์คํ๋ง ์ปจํ ์ด๋๋ ๋ค์ํ ํ์์ ์ค์ ์ ๋ณด๋ฅผ ๋ฐ์๋๋ฆด ์ ์๊ฒ ์ ์ฐํ๊ฒ ๋ง๋ค์ด ๋์ ๊ฒ์ด์์.
์ฐ๋ฆฌ๋ ์ด๊ฒ์ ํตํด ์๋ฐ ์ฝ๋, XML, Groovy ๋ฑ์ ์ฌ์ฉํ ์ ์๋ต๋๋ค!
๐ Annotation ๊ธฐ๋ฐ Java Code Configuration ์ฌ์ฉ
new AnnotaionConfigApplicationContext(AppConfig.class);
AnnotationConfigApplicationContext ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ฉด์ ์๋ฐ ์ฝ๋๋ก ์ด๋ฃจ์ด์ง ์ค์ ์ ๋ณด๋ฅผ ๋๊ธฐ๋ฉด ๋๋ ๊ฒ์ด์์.
๐ XML Configuration ์ฌ์ฉ
์ต๊ทผ์๋ ์คํ๋ง ๋ถํธ๋ฅผ ๋ง์ด ์ฌ์ฉํ๋ฉด์ XML ๊ธฐ๋ฐ ์ค์ ์ ์ ์ฌ์ฉํ์ง ์๋๋ค๊ณ ํฉ๋๋ค!
ํ์ง๋ง, ์์ง ๋ง์ ๋ ๊ฑฐ์ ํ๋ก์ ํธ๋ค์ด XML๋ก ์ด๋ค์ ธ ์๊ณ , ๋ XML์ ์ฌ์ฉํ๋ฉด Compile ์์ด ๋น ์ค์ ์ ๋ณด๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ ์ฅ์ ๋ ์๋ ๊ฒ์ด์์.
GenericXmlApplicationContext๋ฅผ ์ฌ์ฉํ๋ฉฐ, 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>
<bean id = "memberRepository" class = "hello.core.member.MemoryMemberRepository"/>
<bean id = "orderService" class = "hello.core.orderImsi.OrderServiceImpl">
<constructor-arg name = "memberRepository" ref = "memberRepository"/>
<constructor-arg name = "discountPolicy" ref = "discountPolicy"/>
</bean>
<bean id = "discountPolicy" class = "hello.core.discount.RateDiscountPolicy"/>
</beans>
package hello.core.xml;
import hello.core.member.MemberService;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class XmlAppContextTest {
@Test void xmlAppContext() {
ApplicationContext ac = new GenericXmlApplicationContext("appConfig.xml");
MemberService memberService = ac.getBean("memberService", MemberService.class);
Assertions.assertThat(memberService).isInstanceOf(MemberService.class);
}
}
XML ๊ธฐ๋ฐ์ appConfig.xml ์คํ๋ง ์ค์ ์ ๋ณด์ ์๋ฐ ์ฝ๋๋ก ๋ AppConfig.java ์ค์ ์ ๋ณด๋ฅผ ๋น๊ตํด ๋ณด๋ฉด ๊ฑฐ์ ๋๊ฐ์ ๊ฒ์ด์์.
๐์คํ๋ง ๋น ์ค์ ๋ฉํ ์ ๋ณด - BeanDefintion
์คํ๋ง์ ์ด๋ป๊ฒ ์ด๋ฐ ๋ค์ํ ์ค์ ํ์์ ์ง์ํ๋ ๊ฒ์ผ๊น์? ๊ทธ ์ค์ฌ์๋ BeanDefinition์ด๋ผ๋ ์ถ์ํ๋ก ์ด๋ค์ง ์น๊ตฌ๊ฐ ์๋ ๊ฒ์ด์์.
ํ๋ง๋๋ก ์ด๊ฒ ์ญ์ '์ญํ ๊ณผ ๊ตฌํ์ ๊ฐ๋ ์ ์ผ๋ก ๋๋ ๊ฒ' ์ด์ง์.
์ด๊ฒ์ XML์ ์ฝ์ด์ BeanDefinition์ ๋ง๋ค๋ฉด ๋๋ ๊ฒ์ด์์. ํน์ ์๋ฐ ์ฝ๋๋ฅผ ์ฝ์ด BeanDefinition์ ๋ง๋ค๋ฉด ๋๋ ๊ฒ์ด์ง์.
์คํ๋ง ์ปจํ ์ด๋๋ ์๋ฐ ์ฝ๋์ธ์ง XML์ธ์ง ์๊ด ์์ด์! 'I don't care'์ธ ๊ฒ์ด์ด์ฃ . ์ค์ง BeanDefinition๋ง ์๋ฉด ๋๋ ๊ฒ์ด์์.
BeanDefinition์ ๋น ์ค์ Meta Information (๋ฉํ ์ ๋ณด)๋ผ๊ณ ํ๋ ๊ฒ์ด์์.
์๋ฐ ์ฝ๋์์๋ @Bean XML์์๋ <bean>์ผ๋ก ๊ฐ๊ฐ ํ๋์ฉ Meta Information์ด ์์ฑ๋๋ต๋๋ค!
์คํ๋ง ์ปจํ ์ด๋๋ ์ด ๋ฉํ์ ๋ณด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์คํ๋ง ๋น์ ์์ฑํ๋ ๊ฒ์ด์์.
AnnotaionConfigApplicationContext๋ AnnotatedBeanDefinitionReader๋ฅผ ์ฌ์ฉํ์ฌ AppConfig.class๋ฅผ ์ฝ์ด ์จ ๋ค BeanDefinition์ ๋ง๋๋ ๊ฒ์ด์์.
๋ํ, GenericXmlApplicationContext๋ XmlBeanDefinitionReader๋ฅผ ์ฌ์ฉํ์ฌ appConfig.xml์ ์ฝ์ด ์จ ๋ค BeanDefinition์ ๋ง๋๋ ๊ฒ์ด์์.
๋ง์ฝ ๊ฐ๋ฐ์๊ฐ ์ค์ค๋ก ์๋ก์ด ํ์์ ์ค์ ์ ๋ณด๊ฐ ์ถ๊ฐํ๋ ค๋ฉด, XxxBeanDefinitionReader๋ฅผ ๋ง๋ค์ด BEanDefinition์ ๋ง๋ค๋ฉด ๋๋ ๊ฒ์ด์์.
๐ BeanDefinition Information
- BeanClassName : ์์ฑํ ๋น์ ํด๋์ค ์ด๋ฆ(์๋ฐ ์ค์ ์ฒ๋ผ Factory ์ญํ ์ ๋น์ ์ฌ์ฉํ๋ฉด ์์)
- factoryBeanName : Factory ์ญํ ์ ๋น์ ์ฌ์ฉํ ๊ฒฝ์ฐ ์ด๋ฆ ์:) appConfig
- factoryMethodName : ๋น์ ์์ฑํ Factory Method ์ง์ ์:) memberService
- Scope : ์ฑ๊ธํค(Defulat Value)
- lazyinit : ์คํ๋ง ์ปจํ
์ด๋๋ฅผ ์์ฑํ ๋, ๋น์ ์์ฑํ๋ ๊ฒ์ด ์๋๋ผ, ์ค์ ๋น์ ์ฌ์ฉํ ๋๊น์ง ์ต๋ํ ์์ฑ์ ์ง์ฐ์ฒ๋ฆฌ ํ๋์ง ์ฌ๋ถ
JPA์์ N + 1๋ฌธ์ ์ ํด๊ฒฐ ๋ฐฉ์์์ ๋ ๋์ค๋ ๊ฐ๋ - InitMethodName : ๋น์ ์์ฑํ๊ณ , ์์กด๊ด๊ณ๋ฅผ ์ ์ฉํ ๋ค ํธ์ถ๋๋ ์ด๊ธฐํ Method ์ด๋ฆ
- DestoryMethodName : ๋น์ ์๋ช ์ฃผ๊ธฐ๊ฐ ๋๋์ ์ ๊ฑฐํ๊ธฐ ์ง์ ํธ์ถ๋๋ Method ์ด๋ฆ
- Constructor arguments, Properties : ์์กด๊ด๊ณ ์ฃผ์ ์์ ์ฌ์ฉ (์๋ฐ ์ค์ ์ฒ๋ผ Factory ์ญํ ์ ๋น ์ฌ์ฉ ์ ์์)
package hello.core.beandefinition;
import hello.core.AppConfig;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class BeanDefinitionTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test @DisplayName("Bean Configuration Meta Information Check")
void findApplicationBean() {
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
System.out.println("beanDefinitionName = " + beanDefinitionName + "\n beanDefinition ์์ฒด ์ถ๋ ฅ = " + beanDefinition);
} // if ๋ฌธ ๋
} // for ๋ฌธ ๋
} // findApplicationBean() ๋
} // Class ๋
package hello.core.beandefinition;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.support.GenericXmlApplicationContext;
public class BeanDefinitionTestForXml {
// ๋ณ์ ์๋ฃํ ํ์
์ ApplicationContext๋ก ํ์ง ์๋ ์ด์ ๋ ๊ทธ๋ ๊ฒ ํ๋ฉด getBeanDefinition์ ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ
GenericXmlApplicationContext ac = new GenericXmlApplicationContext("appConfig.xml");
@Test @DisplayName("Bean Configuration Meta Information Check For XML")
void findApplicationBean() {
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
System.out.println("beanDefinitionName = " + beanDefinitionName + "\n beanDefinition ์์ฒด ์ถ๋ ฅ = " + beanDefinition);
} // if ๋ฌธ ๋
} // for ๋ฌธ ๋
} // findApplicationBean() ๋
} // Class ๋
์ ๋ฆฌํ์๋ฉด
BeanDefinition์ ์ง์ ์์ฑํ์ฌ ์คํ๋ง ์ปจํ ์ด๋์ ๋ฑ๋กํ ์๋ ์๋ต๋๋ค! ํ์ง๋ง, ์ด๋ ๊ฒ ํ๋ ๊ฒฝ์ฐ๋ ๊ฑฐ์ ์๋ค๊ณ ํ๋ค์!
๊ฐ๋ ์คํ๋ง ์ฝ๋๋ ์คํ๋ง ๊ด๋ จ ์คํ ์ํ ์ฝ๋๋ฅผ ๋ณด๋ฉด BeanDefiniton์ด๋ผ๋ ๊ฒ์ด ๋ณด์ผ ๋๊ฐ ์๋๋ฐ, ์ด ๋ ์ค๋ ๊ณต๋ถํ ๋ด์ฉ์ ๋ ์ฌ๋ฆฌ๋ฉด ๋๋ ๊ฒ์ด์์!
์ฃผ๋ํ๋์ ๊ธ์ด ๋ง์์ ๋์
จ๋์? ๊ตฌ๋
๊ณผ ๊ณต๊ฐ! ๊ทธ๋ฆฌ๊ณ , ๋๊ธ ๊ทธ๋ฆฌ๊ณ ๋ฐฉ๋ช
๋ก์ ์ฃผ๋ํ๋์๊ฒ ๋ง์ ํ์ด ๋ฉ๋๋ค
'Back-End ์์ ์ค > Spring Framework' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[JPA] @ManyToOne (0) | 2021.10.05 |
---|---|
[Spring] ์ฑ๊ธํค ์ปจํ ์ด๋ (0) | 2021.10.05 |
[Spring] Ioc, DI Container (0) | 2021.10.01 |
[Spring] AppConfig ๋ฆฌํฉํฐ๋ง (0) | 2021.09.30 |
[Spring] ๊ฐ์ฒด ์งํฅ ์๋ฆฌ ์ ์ฉ - ์๋ก์ด ํ ์ธ ์ ์ฑ ๊ฐ๋ฐ (0) | 2021.09.29 |