์ƒ์„ธ ์ปจํ…์ธ 

๋ณธ๋ฌธ ์ œ๋ชฉ

[Spring] Spring IoC Container, BeanScan, ์ƒ๋ช…์ฃผ๊ธฐ, ์Šค์ฝ”ํ”„

๐Ÿ˜Ž ์ง€์‹ in Action/Spring ๐ŸŒฑ

by :ํ•ดํ”ผ๋ž˜๋น—๐Ÿพ 2024. 11. 20. 17:03

๋ณธ๋ฌธ

728x90

IoC 

- ์ œ์–ด์˜ ์—ญ์ „ : ๊ฐ์ฒด์˜ ์ƒ์„ฑ์—์„œ๋ถ€ํ„ฐ ์ƒ๋ช…์ฃผ๊ธฐ์˜ ๊ด€๋ฆฌ๊นŒ์ง€ ๋ชจ๋“  ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ œ์–ด๊ถŒ์ด ๋ฐ”๋€Œ์—ˆ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธ 

 

1) DI : Dependency Injection 

์ƒ์„ฑ์ž, ํ•„๋“œ, setter 

๋™์ ์œผ๋กœ ์˜์กด์„ฑ ์ฃผ์ž… -> ์‘์ง‘๋„ ๋‚ฎ์ถค

๋””๋ฒ„๊น… ์–ด๋ ค์›€ + ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์งœ๊ธฐ ์–ด๋ ค์›€

 

2) DL : Depnedency LookUp 

์˜์กด๊ด€๊ณ„๊ฐ€ ํ•„์š”ํ•œ ๊ฐ์ฒด์—์„œ ์ง์ ‘ ๊ฒ€์ƒ‰ํ•˜๋Š” ๋ฐฉ์‹

 

"์Šคํ”„๋ง ๋‚ด"์—์„œ

1) ์ƒ์„ฑ์ž ์ฃผ์ž… 

- ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ๋•Œ, ์˜์กด์„ฑ์„ ๊ฐ•์ œํ•  ์ˆ˜ ์žˆ์Œ

private final MasterService; 

MentorController(MasterService masterService ){

   this.masterService = masterService;

}

- ์ˆœํ™˜์ฐธ์กฐ ์˜ˆ๋ฐฉ

 

2)  ํ•„๋“œ ์ฃผ์ž…

 

3) setter

- ํ•„์š”ํ•  ๋•Œ๋งŒ ์™ธ๋ถ€์—์„œ ๋ฐ›์•„์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

 

IoC Container๊ฐ€ ์™œ ํ•„์š”ํ•œ๊ฐ€

1) ์ „์—ญ์ ์œผ๋กœ ๊ฐ์ฒด๊ฐ„์˜ ์˜์กด๊ด€๊ณ„๋ฅผ ์„ค์ •

2) ๋ฐ˜๋ณต์ ์ธ ๊ฐ์ฒด ์ƒ์„ฑ x

BeanFactory์˜ ํ•˜์œ„ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ApplicationContext๊ฐ€ Spring์—์„œ ๋งํ•˜๋Š” IoC Container๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค

 

IoC Container ๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ์„œ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ์žฅ์ 

๊ฐ์ฒด ์˜์กด์„ฑ์„ ์—ญ์ „์‹œ์ผœ ๊ฐ์ฒด ๊ฐ„์˜ ๊ฒฐํ•ฉ๋„๋ฅผ ์ค„์ด๊ณ , ์œ ์—ฐํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜์—ฌ

๊ฐ€๋…์„ฑ ๋ฐ ์ฝ”๋“œ ์ค‘๋ณต, ์œ ์ง€ ๋ณด์ˆ˜๋ฅผ ํŽธํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Œ

 

์–ด๋–ค ๊ธฐ๋Šฅ์„ ํ™•์žฅํ–ˆ๋Š”๊ฐ€

ApplicationContext์˜ ๋˜๋‹ค๋ฅธ ๊ธฐ๋Šฅ์œผ๋กœ๋Š” AOP์™€์˜ ์‰ฌ์šด ํ†ตํ•ฉ, ๋ฉ”์‹œ์ง€ ๋ฆฌ์†Œ์Šค ์ฒ˜๋ฆฌ(๊ตญ์ œํ™”), ์ด๋ฒคํŠธ ๊ฒŒ์‹œ๊ฐ€ ์žˆ๋‹ค 

 

 

ApplicationContext ์˜ ์ƒ์† ํด๋ž˜์Šค ๋กœ ์ธํ•ด ์ž๋ฐ”์ฝ”๋“œ, XML ๋“ฑ์œผ๋กœ ์„ค์ • ๊ฐ€๋Šฅ

1) AnnotationConfigApplicationContext(AppConfig.class)

2) GenericXmlApplicationContext(appConfig.xml)

 

์Šคํ”„๋ง ๋นˆ ์ด๋ฒคํŠธ ๋ผ์ดํ”„ ์‚ฌ์ดํด

IoC Container ์ƒ์„ฑ -> ๋นˆ ์ƒ์„ฑ -> ์˜์กด ๊ด€๊ณ„ ์ฃผ์ž… -> ์ดˆ๊ธฐํ™” ์ฝœ๋ฐฑ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ@PostConstruct -> ์‚ฌ์šฉ -> ์†Œ๋ฉธ์ „ ์ฝœ๋ฐฑ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ@PreDestroy -> ์Šคํ”„๋ง ์ข…๋ฃŒ

 

 

Spring Container : ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ๊ด€๋ฆฌ

์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋Š” ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ฒŒ ์„ค๊ณ„ํ•˜๋ฉด ์•ˆ๋œ๋‹ค 

๋ฌด์ƒํƒœ๋กœ ์„ค๊ณ„ํ•ด์•ผ ํ•œ๋‹ค

1) ํŠน์ • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์˜์กด์ ์ธ ํ•„๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ์•ˆ๋œ๋‹ค

2) ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋Š” ํ•„๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ์•ˆ๋œ๋‹ค

 

public class StatefulService {
	private int price; // ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋Š” ํ•„๋“œ
    public void order(String name, int price){
    	System.out.println("name= "+ name + " price = " + price);
    	this.price = price; // ์—ฌ๊ธฐ๊ฐ€ ๋ฌธ์ œ!
    }
    public int getPrice(){
    	return price;
    }
}

 

public class StatefulServiceTest {

	@Test
    void statefulServiceSingleton() {
    	ApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
        StatefulService statefulService = ac.getBean("statefulService", StatefulService.class);
        StatefulService statefulService2 = ac.getBean("statefulService", StatefulService.class);
        
        statefulService.order("userA", 10000);
        statefulService2.order("userB", 20000);
        
        int price = statefulService.getPrice();
        System.out.println(price); // 20000
        
        Assertions.assertThat(statefulService.getPrice()).isEqualTo(20000);
        
    }
    
    static class TestConfig {
    	@Bean
        public StatefulService statefulService(){
        	return new StatefulService();
        }
    
    }
}

 

 

@Configuration์„ ์ ์šฉํ•œ AppConfigํด๋ž˜์Šค๋Š”

CGLIB๊ฐ€ ๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ์กฐ์ž‘ํ•˜์—ฌ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ๋ณด์žฅํ•œ๋‹ค

@Bean
public MemberRepository memberRepository() {
	if(memberRepository๊ฐ€ ์ด๋ฏธ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก๋˜์–ด  ์žˆ์Œ){
    	return ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์—์„œ ์ฐพ์•„์„œ ๋ฐ˜ํ™˜;
    } else {
    	๊ธฐ์กด ๋กœ์ง์„ ํ˜ธ์ถœํ•ด์„œ ์ƒ์„ฑํ•˜๊ณ  ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก
        return ๋ฐ˜ํ™˜;
    }
}

 

์ปดํฌ๋„ŒํŠธ ์Šค์บ”

@ComponentScan

@Component ๊ฐ€ ๋ถ™์€ ๋ชจ๋“  ํด๋ž˜์Šค๋ฅผ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก

basePackages : ํ•„์š”ํ•œ ์œ„์น˜๋ถ€ํ„ฐ ํƒ์ƒ‰ํ•˜๋„๋ก ์‹œ์ž‘ ์œ„์น˜ ์ง€์ •

@SpringBootApplication ์•ˆ์— @ComponentScan์ด ๋“ค์–ด์žˆ์Œ

 

@Controller : ์Šคํ”„๋ง MVC ์ปจํŠธ๋กค๋Ÿฌ

@Repository : ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๊ณ„์ธต์œผ๋กœ ์ธ์‹, ๋ฐ์ดํ„ฐ ๊ณ„์ธต์˜ ์˜ˆ์™ธ๋ฅผ ์Šคํ”„๋ง ์˜ˆ์™ธ๋กœ ๋ณ€ํ™˜

@Configuration : ์Šคํ”„๋ง ์„ค์ • ์ •๋ณด๋กœ ์ธ์‹, ์Šคํ”„๋ง ๋นˆ์ด ์‹ฑ๊ธ€ํ†ค์„ ์œ ์ง€ํ•˜๋„๋ก ์ถ”๊ฐ€ ์ฒ˜๋ฆฌ

@Service : ๋น„์ฆˆ๋‹ˆ์Šค ๊ณ„์ธต ์ธ์‹ ๋„์›€ 

 

์ปดํฌ๋„ŒํŠธ ์Šค์บ” ์ œ์™ธ 

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyIncludeComponent {}

 

@ComponentScan(
  includeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class), 
  excludeFilters = @Filter(type= FilterType.ANNOTATION, classess = MyExcludeComponent.class)
)

 

@Autowired

์ž๋™์œผ๋กœ ํƒ€์ž…์ด ๊ฐ™์€ ์Šคํ”„๋ง ๋นˆ์„ ์ฐพ์•„์„œ ์ฃผ์ž…

 

์šฐ์„ ์ˆœ์œ„

1. ํ•„๋“œ๋ช… ๋งคํ•‘

2. @Qualifier ๋ผ๋ฆฌ ๋งค์นญ > ๋นˆ ์ด๋ฆ„ ๋งค์นญ

3. @Primary : ์šฐ์„ ์ˆœ์œ„ ์ •ํ•˜๊ธฐ 

 

 

์ˆ˜๋™๋นˆ ๋“ฑ๋ก 

-> ์—…๋ฌด ๋กœ์ง ๋นˆ : ๋น„์ฆˆ๋‹ˆ์Šค ์š”๊ตฌ์‚ฌํ•ญ 

-> ๊ธฐ์ˆ  ์ง€์› ๋นˆ : AOP๋‚˜ ๊ธฐ์ˆ ์ ์ธ ๋ฌธ์ œ ์ฒ˜๋ฆฌํ•  ๋•Œ, ๊ณตํ†ต ๋กœ๊ทธ ์ฒ˜๋ฆฌ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ

 

 

๋นˆ ์ƒ๋ช…์ฃผ๊ธฐ ์ฝœ๋ฐฑ

- ์ธํ„ฐํŽ˜์ด์Šค (InitializingBean, DisposableBean)

์ƒ์†๋ฐ›์•„์„œ afterPropertiesSet()๋ฉ”์„œ๋“œ๋กœ ์ดˆ๊ธฐํ™” ์ง€์›, destroy()๋ฉ”์„œ๋“œ๋กœ ์†Œ๋ฉธ ์ง€์›

 

- ์„ค์ • ์ •๋ณด์— ์ดˆ๊ธฐํ™” ๋ฉ”์„œ๋“œ, ์ข…๋ฃŒ ๋ฉ”์„œ๋“œ ์ง€์ •

@Bean์˜ destroyMethod ์†์„ฑ์—์„œ close, shutdown ์ด๋ฆ„์˜ ์ข…๋ฃŒ ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ

@Bean(initMethod="init", destroyMethod="close")

 

- @PostConstruct @PreDestroy ์–ด๋…ธํ…Œ์ด์…˜ ์ง€์›

์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ ์šฉ x

 

 

๋นˆ ์Šค์ฝ”ํ”„

1) ์‹ฑ๊ธ€ํ†ค : ๊ธฐ๋ณธ ์Šค์ฝ”ํ”„, ์‹œ์ž‘-์ข…๋ฃŒ

@Test
void singletonBeanFind() {
	AnnotationConfigApplicationContext ac = new AnnotationConfigApplicatiohnContext(Singleton.class);
    SingletonBean singletonBean1 = ac.getBean(SingletonBean.class);
    SingletonBean singletonBean2 = ac.getBean(SingletonBean.class);
    assertThat(singletonBean1).isSameAs(singletonBean2);
    ac.close();
}
@Scope("singleton")
static class SingletonBean {
	@PostConstruct
    public void init(){
    	System.out.println("init");
    }
    @PreDestroy
    public void destroy(){
    	System.out.println("destroy");
    }
}

 

2) ํ”„๋กœํ† ํƒ€์ž… : ๋นˆ์˜ ์ƒ์„ฑ๊ณผ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…๊นŒ์ง€๋งŒ ๊ด€์—ฌ, ๋”๋Š” ๊ด€๋ฆฌ x, @PreDistory ๊ฐ™์€ ์ข…๋ฃŒ ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š์Œ

์ฃผ์ž… ๋ฐ›๋Š” ์‹œ์ ์— ๊ฐ๊ฐ ์ƒˆ๋กœ์šด ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์ด ์ƒ์„ฑ๋จ

 

 

ํ”„๋กœํ† ํƒ€์ž… ์Šค์ฝ”ํ”„ + ์‹ฑ๊ธ€ํ†ค ๋นˆ๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ์‹œ Provider๋กœ ๋ฌธ์ œ ํ•ด๊ฒฐ

์˜์กด๊ด€๊ณ„๋ฅผ ์ฃผ์ž…๋ฐ›๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์ง์ ‘ ์˜์กด๊ด€๊ณ„ ์ฐพ๋Š” ๊ฒƒ์„ Dependency Lookup(DL)์ด๋ผ๊ณ  ํ•œ๋‹ค 

ObjectFactory, ObjectProvider

 

 

3) ์›น ๊ด€๋ จ ์Šค์ฝ”ํ”„ : request(์š”์ฒญ๋“ค์–ด์˜ค๊ณ ๋‚˜๊ฐˆ๋•Œ๊นŒ์ง€), session(์›น์„ธ์…˜), application(์„œ๋ธ”๋ฆฟ์ปจํ…์ŠคํŠธ์™€ ๊ฐ™์€ ๋ฒ”์œ„)

์Šคํ”„๋ง ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•˜๋Š” ์‹œ์ ์— request ์Šค์ฝ”ํ”„ ๋นˆ์€ ์ƒ์„ฑ๋˜์ง€ ์•Š์Œ -> ์‹ค์ œ ๊ณ ๊ฐ์˜ ์š”์ฒญ์ด ๋“ค์–ด์™€์•ผ ์ƒ์„ฑ๋จ

๊ทธ๋ž˜์„œ, ๋ฏธ๋ฆฌ Proxy ํด๋ž˜์Šค๋ฅผ ๋‹ค๋ฅธ ๋นˆ์— ๋ฏธ๋ฆฌ ์ฃผ์ž…ํ•จ 

 

@Component

@Scope(value="request", proxyMode = ScopedProxyMode.TARGET_CLASS) 

public class MyLogger {

  private String uuid,  requestURL;

  public void log(String message){

   System.out.println(uuid+" "+requestURL+" "+message);

  }

  @PostConstruct

  public void init(){

  }

   @PreDestroy

    public void close() {

    }  

}

 

 

ํ”„๋ก์‹œ 

- CGLIB ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ํด๋ž˜์Šค ์ƒ์† ๋ฐ›์€ ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด

- ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ์‹ค์ œ request scope์™€๋Š” ๊ด€๊ณ„ ์—†์Œ

 

 

728x90

๊ด€๋ จ๊ธ€ ๋”๋ณด๊ธฐ