본문 바로가기
spring & boot/Spring & Spring Boot

[Spring] Spring-Container, IoC, DI, Singleton 개념 정리

by lucas_owner 2023. 2. 8.

목차

  1. IoC 란? 
  2. Spring Container (스프링 컨테이너)
  3. DI(Dependency Injection) 란?
  4. Singleton 패턴이란?

 

IoC 란? 

  • IoC 란 Inversion Of Control의 약자이며, 제어의 역전 이라고 한다.
  • 프로그래머와 프레임워크의 주체가 바뀌었다고 표현한다.
    • 일반적인 경우라면 '개발자'가 미리 정한 순서에 따라 생성, 실행을 주도, 의도 했다면(개발자가 제어권을 가졌다.)
    • IoC 가 등장한 이후는 객체의 생성, 생명주기, 관리까지 모든 객체에 대한 주도권을 프레임워크가 가진것이다.(프레임워크가 관리)
  • IoC 를 통해 Application을 구성하는 객체 간의 낮은 결합도를 유지할 수 있다. 
  • IoC 의 역할을 담당하는것이 Spring Container 이다. (Spring Container가 IoC를 담당한다.)
  • Spring ContaIner를 IoC Container 라고도 한다. 

 

Spring Container (스프링 컨테이너) = IoC Container

- Spring Container 란?

 

스프링 컨테이너는 Spring Application 내에서 자바 객체를 관리하는 공간을 뜻한다.

자바 객체를 Bean(빈) 이라고 Spring 에서는 부른다.

 

컨테이너의 역할은 의존성 주입(DI, Dependency Injection)을 통하여 Application을 구성하는 빈(Bean)들의 생명주기(Life Cycle)을 개발자 대신 관리해준다. (Bean의 생성, 소멸 관리)

 

IoC 에서 설명했듯, Spring 에서 IoC를 담당하는 컨테이너를 뜻한다고 보면된다.

 

 

스프링 컨테이너의 종류에는 크게 2가지로 나누고는 한다. 

  • BeanFactory
  • ApplicationContext

Spring 공식문서 상 컨테이너를 사용해야 할때 특별한 이유가 없다면, ApplicationContext 를 사용하라고 권장한다.

그 이유는 BeanFactory(인터페이스, 최상위) <- ApplicationContext(인터페이스) <- ApplicationContext(구현체) 의 구조이며,

BeanFactory의 모든 기능을 ApplicationContext가 포함하고 있고, 추가기능까지 있기 때문이다.

 

 

DI (Dependency Injection) 란? 

- DI 란 Dependency Injection 의 약자이며, 의존 관계 주입(의존성 주입) 이라고 불린다. 

- new(객체를 직접 생성)으로 생성하는것이 아닌, 외부에서 생성된 객체를 주입받아 사용하는것. 

 

- IoC 가 행하여 질때, Spring 내부의 객체들간의 관계를 관리할 때 사용하는 기법이다.

  • 강하게 결합된 Class 를 분리.
  • Application 실행 시점에 객체 간의 관계를 결정, 주입 해준다.
  • 결합도를 낮추고 유연성을 확보한다.

 

- 왜 사용해야 하는가? 에 대한 의문이 생길것이다. 

간단하게 설명하고 예제를 보겠다. 

 

- 우선 객체를 생성하는 방법은 우리 모두가 알고있다.

아래와 같이 new 키워드를 사용하여 간단하게 생성이 가능하지 않은가?

MemberDao dao = new MemberDao();

- 하지만 이 방법에는 단점이 존재한다. 객체 를 자주, 많이 사용한다고 생각 해보자. 

그럼 Application 내부에서는, Client 한명한명이 접근을 할 때 마다, 객체를 생성, 사용 하게 된다. 

디테일한 개념을 몰라도 이 방법이 얼마나 비효율적인지에 대해서는 알 수 있을것이다. 

이러한 단점을 해결하기 위한 방법으로 Singleton(싱글톤) 패턴이 사용된다. 

 

* Singleton 패턴에 대한건 아래에서 설명 하도록 하고, DI 에 대해서 계속 보자.

 

- DI 를 하기위한 방법은 3가지가 존재한다.

  1. 생성자 주입
  2. 필드 주입
  3. Setter(수정자) 주입

Spring 에서는 1번. 생성자 주입을 권장한다. (Setter 주입의 경우, 객체가 변경될 필요성이 존재할 때 사용! -> 하지만 그런 경우는 드물다.)

 

○ 생성자 주입을 사용해야하는 이유

-객체의 불변성 확보: 객체의 생성자는 객체 생성시 1번만 호출된다, 그렇기 때문에 주입받은 객체가 불변객체 이거나, 반드시 객체의 주입이 필요할 경우에만 사용 하기때문이다. (재 생성이 될일이 없거나, 객체가 변하지 않을경우를 의미함.)

 

- 순환참조 에러 방지: A, B 2개의 Class 가 있다고 가정을 했을 때, A 는 B객체를 참조하고, B는 A 객체를 참조하는 경우,

서로 메서드를 계속 호출 하기 때문에 StackOverFlow 가 발생하면서, Application 이 다운된다.(A 또는 B 클래스를 호출 하는 경우 발생)

 

- 생성자 주입 예제

@Controller
public class Controller {

	private Service service;
    
    @Autowired
    public Controller(Service service) {
    	this.service = service;
    }
}

 

- 생성자 주입 예제 - Lombok

@Controller
@RequiredArgsConstructor // final 키워드가 붙은 필드를 포함하여 생성자를 만들어준다.
public class Controller {

	private final Service service;
    
 
}

 

Singleton 패턴이란?

- 해당 객체를 1개만 생성하여, 필요한 곳에서 공유하는 방법.

- new 를 사용하여 호출 할 때 마다 객체를 생성하는 방법이 아니다. (메모리 낭비 방지)

- Spring Container 는 기본적으로 객체를(Bean)을 Singleton으로 생성, 관리한다. 

 

- 싱글톤 생성 방법. 

public class Singleton {

	// Class 로딩 시점에 생성, Static 이기 때문에 1개만 생성됨.
	private static final Singleton instance = new Singleton();
    
    // 생성자: private 으로, 외부 클래스에서 인스턴스 생성 방지.
    private Singleton(){}; 
    
    public static Singleton getInstance() {
    	return instance;
    }
}

 

- Spring Container 에 Singleton 객체 등록

- Spring Container 는 기본적으로 객체들을 싱글톤으로 관리한다. 

- @Configuration 이 붙어있는 Class 내부에서 @Bean 어노테이션이 붙은 객체들은 싱글턴 패턴적용을 받고,
   스프링 컨테이너에서 관리하게된다.

 

@Configuration
public class springConfig {

	@Bean
    public MemberDao memberDao(){return new MemberDao()};
    
}
  • Spring 에서 @Controller, @Service, @Repository 와 같은것들을 class에 선언하면, 
    스프링 컨테이너에 자동으로 등록되고 관리된다. !! 

 

- Singleton : Java Code로 구현

public class singletone {

	static singletone object;
	static int count; // 객체가 몇번 생성되었는지 확인
	
	private singletone() {
		System.out.println("싱글톤 객체 생성됨.");
		count++;
	}
	
	public static singletone getInstance() {
		if (object == null) {
			object = new singletone();
		} else {
			System.out.println("이미 객체가 생성됨");
		}
		return object;
	} // getinstance
	
	
}// class

- Java 코드로 싱글톤(singleton)을 구현하는것은 위와 같다. 

- 객체가 생성되고, 해당 객체를 사용 시점 -> getInstace() 시점에 객체가 생성되지 않았다면 객체 생성 후 해당 객체를 return

이미 생성되어 있다면, 생성되어있는 객체를 return 한다. 

반응형

댓글