본문 바로가기
4. Backend Development/1. Spring Framework

2. Spring IoC Container

by H232C 2020. 4. 30.

1. IoC 컨테이너와 빈

- IoC(Inversion of Control) :  DI(Dependency Injection)이라고도 하며, 어떤 객체가 사용하는 의존 객체를 직접 만들어 사용하지 ㅋ않고 주입받아 사용하는 방법을 말함

- Spring IoC 컨테이너 : Beanfactory, ApplicationContext (Beanfactory 인터페이스를 Implements 함) : 어플리케이션 컴포넌트의 중앙 저장소이면서 빈 설정 소스로 부터 빈 정의를 읽고 빈을 구성하여 제공

빈의 역할 Spring IoC 컨테이너가 관리하는 객체
장점
의존성 관리 의존하는 관계의 객체간의 인스턴스 생성을 컨트롤함으로 의존성을 효율적으로 관리
테스트 용이 Mock과 같은 가짜 객체를 만들어 Return 값 조작 가능(의존성 주입이 안된 상태로 의존 관계의 코드의 단위 테스트 어려움)
스코프 싱글톤(기본적으로 Spring IoC Container에서 Bean을 생성할 때 싱글톤 디자인 패턴을 이용하여 생성함, 하나의 객체를 재사용하는 구조이므로 효율적이며 성능이 우수함)
라이프사이클 인터페이스 @PostConstruct 등의 어노테이션을 이용하여 빈의 생명주기를 관리하고 특정 시점에 원하는 기능을 수행하게 할 수 있음


- 빈 생성, 주입 과정(XML 파일을 이용한 빈 관리)

// application.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="bookService" class="me.whiteship.springbootapplicationcontext.BookService">
        <property name="bookRepository" ref="bookRepository" />
<!--        application.xml을 이용해서 빈을 생성하고 주입하는 방식은 아주 고전적인 방식이다.
            bean = bean 등록, property = bean 주입
            name = BookSerivce의 setter, ref = 아래의 bookRepository Bean ID
            즉 name에 지정된 setter가 매개변수로 받을수 있는 형이 name에 들어와야 함
            bookService Bean은 bookRepository라는 id를 가진 bean으로 부터 bookRepository 의존성 주입받음
            이 방법의 단점은 XML에 일일이 등록해줘야 한다는 점이다. 그래서 나온게 context:component-scan 방법임-->
    </bean>

    <bean id="bookRepository" class="me.whiteship.springbootapplicationcontext.BookRepository"></bean>

</beans>

 

 

// BookRepository.class

package me.whiteship.springbootapplicationcontext;
import org.springframework.stereotype.Repository;

public class BookRepository {

}

 

 

// BooService.class

package me.whiteship.springbootapplicationcontext;
import org.springframework.beans.factory.annotation.Autowired;

public class BookService {

    BookRepository bookRepository;
    
    public void setBookRepository(BookRepository bookRepository) {
        this.bookRepository = bookRepository; // BookRepository Bean이 주입됨
    }
}

 


- 빈 생성, 주입 과정(XML 파일에서 Bean을 수동으로 등록하지 않고 자동으로 스캔하여 Bean을 등록)

// application.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <context:component-scan base-package="me.whiteship.springbootapplicationcontext" />
<!--    component-scan 방식은 패키지 내 @Component 어노테이션이 등록된 클래스를 모두 빈으로 등록함
        @Service, @Repository.. 등등의 내부에는 @Component 어노테이션을 쓰고있기때문에
        해당 어노테이션으로 등록해도 스캔이 됨 스프링 2.5부터 적용된 기술
        세번쨰 방법은 ApplicationConfig.class 파일을 만들어서 @Bean 어노테이션으로 등록하는 방법임-->

</beans>

 

 

// BookRepository.class

package me.whiteship.springbootapplicationcontext;

import org.springframework.stereotype.Repository;

@Repository // @CompoentScan, xml의 component-scan 사용시 사용됨
public class BookRepository {

}

 

 

// BookService.class

package me.whiteship.springbootapplicationcontext;

import org.springframework.stereotype.Service;

@Service // @CompoentScan, xml의 component-scan 사용시 사용됨
public class BookService {

    BookRepository bookRepository;
    public void setBookRepository(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }
}

 

 

// DemoApplication.class

package me.whiteship.springbootapplicationcontext;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Arrays;

public class DemoApplication {

	public static void main(String[] args) {

		ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");  //xml로 Bean을 등록할 경우 사용
		String[] beanDefinitionNames = context.getBeanDefinitionNames(); // xml, applicationConfig 사용시
		System.out.println(Arrays.toString(beanDefinitionNames)); // xml, applicationConfig 사용시

		BookService bookService = (BookService) context.getBean("bookService"); // xml, applicationConfig 사용시
		System.out.println(bookService.bookRepository); // 주입된 bookRepository 객체!!! // xml, applicationConfig 사용시
	}
}

 

- 빈 생성, 주입 방법 (class 파일을 이용한 빈 관리 : Bean을 직접 등록)

// BookRepository.class

package me.whiteship.springbootapplicationcontext;

import org.springframework.stereotype.Repository;

@Repository // @CompoentScan, xml의 component-scan 사용시 사용됨
public class BookRepository {

}

 

 

// BookService.class

package me.whiteship.springbootapplicationcontext;

import org.springframework.stereotype.Service;

@Service // @CompoentScan, xml의 component-scan 사용시 사용됨
public class BookService {

    BookRepository bookRepository;
    public void setBookRepository(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }
}

 

 

// ApplicationConfig.class

package me.whiteship.springbootapplicationcontext;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

public class ApplicationConfig {

    @Bean // ApplicationConfig.class를 이용하여 Bean을 "직접" 등록하는 방법
    public BookRepository bookRepository(){
        return new BookRepository();
    }

    @Bean
    public BookService bookService(){
        BookService bookService = new BookService();
        bookService.setBookRepository(bookRepository()); // 의존성 주입, 이렇게 하지 않고 @Autowired로 바로 주입가능 (Setter를 사용)
        return bookService;

//        return new BookService(); // BookService의 BookRepository bookrepository 위에 @Autowired를 사용한다면 이렇게도 의존성 주입 가능
    }
}

 

 

// DemoApplication.class

package me.whiteship.springbootapplicationcontext;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Arrays;

public class DemoApplication {

	public static void main(String[] args) {
		ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class); // ApplicationConfig 파일로 등록할 경우 사용
		String[] beanDefinitionNames = context.getBeanDefinitionNames(); // xml, applicationConfig 사용시
		System.out.println(Arrays.toString(beanDefinitionNames)); // xml, applicationConfig 사용시
		BookService bookService = (BookService) context.getBean("bookService"); // xml, applicationConfig 사용시
		System.out.println(bookService.bookRepository); // 주입된 bookRepository 객체!!! // xml, applicationConfig 사용시
	}
}

 

- 빈 생성, 주입 방법 (class 파일을 이용한 빈 관리 : Bean을 자동 등록)

package me.whiteship.springbootapplicationcontext;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

@Configuration
@ComponentScan(basePackageClasses = DemoApplication.class) // 메인 클래스부터 관련된 모든 클래스의 @Component 어노테이션을 스캔해라
// 이 방법이 현재 스프링부트에서 사용하고 있는 방법과 가장 가까운 방법이다.
// 스프링부트가 ApplicationConfig 파일조차 자동으로 생성하여 개발자 입장에서는 몰라도되게끔함
// @SpringBootApplication 어노테이션임
public class ApplicationConfig {

}

 

- 빈 생성, 주입 방법(@SpringBootApplication 어노테이션 사용) : 스프링 부트에 해당

package me.whiteship.springbootapplicationcontext;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Arrays;

@SpringBootApplication // 해당 어노테이션만 있다면 @Component 어노테이션이 등록된 클래스를 자동으로 빈으로 등록해줌
// xml이나, ApplicatonConfig를 사용할 필요 없음, SpringBootApplication 내부에 @ComponentScan이 들어가있고 ComponentScan내에 @Configure이 들어가있음
// @SpringBootApplication 자체가 ApplicationConfig 파일과 같다.
public class DemoApplication {
	}
}

 

 

// BookRepository.class

package me.whiteship.springbootapplicationcontext;

import org.springframework.stereotype.Repository;

@Repository // @CompoentScan, xml의 component-scan 사용시 사용됨
public class BookRepository {

}

 

 

// BookService.class

package me.whiteship.springbootapplicationcontext;

import org.springframework.stereotype.Service;

@Service // @CompoentScan, xml의 component-scan 사용시 사용됨
public class BookService {

    BookRepository bookRepository;
    public void setBookRepository(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }
}

 

'4. Backend Development > 1. Spring Framework' 카테고리의 다른 글

6. DispatcherServlet  (0) 2020.09.01
5. Servlet  (0) 2020.09.01
4. MacOS Security Management System  (0) 2020.07.21
3. Spring Framework 기반 웹 프로젝트  (0) 2020.06.09
1. Spring IoC (Inversion of Control)  (0) 2020.04.29

댓글