JAVA

[ Spring ] - IoC컨테이너와 DI

algml0703 2022. 12. 9. 05:21
반응형

IoC컨테이너란?

인스턴스(=객체)의 생명주기를 관리하는 것을 의미하며, 생성된 인스턴스들에게 추가적인 기능을 제공하는 역할도 한다.

* 빈 : 객체를 통해 생성된 인스턴스를 빈이라고 한다.

Bean 생명 주기

컨테이너란?

IoC(Inversion on Control)란?

직역하면 제어의 역전을 의미하며, 개발자가 프로그램의 흐름의 제어하는 것이 아니라, 다른 프로그램에 의해 프로그램의 흐름이 제어되는 것을 의미한다. 예를 들어 의존 관계가 있는 클래스들을 인터페이스를 통해 추상화하여 관리한다면, 개발자는 해당 의존관계에 대한 설정만을 해주고, 실질적인 의존 관계의 연결은 스프링 프레임워크가 맡아 하게 되는 것이다.

** 스프링 IoC 컨테이너 : 스프링 프레임워크로, 의존 관계를 식별하고 인스턴스화하면 연결해주는 역할을 담당한다.

DI(Dependency Injection)란?

 의존성 주입을 의미하는 것으로, 클래스 사이의 의존 관계를 빈(Bean) 설정 정보를 바탕으로 컨테이너가 자동으로 연결해주는 것을 의미한다. 우선 Dependency란 쉽게 이야기하면 클래스 내부에서 참조되는 다른 클래스를 뜻하는 것으로, 예를 들면 아래와 같이 UserController 클래스 실행 시에 생성자 함수에 new를 사용해서 UserService 클래스를 생성하여 사용할 수 있도록 해줄 때, UserService는 UserController의 Dependency이고, 이와 같은 행위를 의존성을 주입해준다고 하는 것이다.

public class UserController {

    private UserService userService;

    public UserController () {
        this.userService = new UserService();
    }
    
}

의존성 주입은 위와 같이 생성자를 통하거나 setter 함수를 통하거나 스프링에서 사용되는 xml파일이나 어노테이션 등을 이용하여 할 수 있다. 

그중에서 빈(Bean) 설정 정보란 말 그대로  각 클래스 간 의존 관계에 대한 설정 정보를 담고 있는 것이라 할 수 있다. Bean은 스프링에서 자바 객체를 의미한다.

의존성 주입은 필드 주입, setter 주입, 생성자 주입 3가지 방식이 존재한다.

 

1. 필드 주입

필드에 바로 의존성을 주입하여 주는 방식이다. 이는 주입한 의존성의 변경이 어렵기 때문에 잘 쓰이지 않으며, 좋은 방식도 아니다. 예를 들어 mysql 데이터베이스를 사용하다가 mongodb로 변경이 불가피하여 데이터베이스가 변경된 경우, 해당 데이터베이스의 구현체를 사용한 곳에서 필드 주입으로 되어 있는 경우 변경이 어려워진다. 이와 같은 형태를 강한 결합 관계를 지니고 있다고 할 수 있다.  아래와 같이 필드에 @Autowired 어노테이션과 함께 사용하면 된다.

@Controller
public class MemberController {
    @Autowired 
    private MemberService memberService;

}

 

2. setter 주입

setter 방식의 문제는 해당 settet를 통해 중간에 변경될 수 있다는 위험이 있다.

@Controller
public class MemberController {
    //
    private MemberService memberService;

    @Autowired
    public void setMemberService(MemberService memberService) {
        this.memberService = memberService;
    }

}

 

3. 생성자 주입

생성자에 의존성을 넣어주는 방식이다. 생성자 주입을 통한 방식이 가장 권장된다.

@Controller
public class MemberController {
    private final MemberService memberService;

    @Autowired
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }
}

빈(Bean)설정방법

스프링 ioc 컨테이너는 어노테이션을 통해 클래스의 인스턴스를 만든다.(즉 빈을 생성한다.)

ex) 의존성 주입 예시

- MemberController파일

package com.example.manageMember.controller;

import org.springframework.stereotype.Controller;

@Controller
public class MemberController {

}

위의 코드를 보면 MemberControoler 클래스 위에 @Controller라는 어노테이션이 사용된 것을 볼 수 있는데, 이와 같이 짜여진 경우 처음에 스프링 컨트이너가 생성될 때 @Controller 어노테이션으로 인해, MemberController클래스의 객체가 생성되어 스프링 컨테이너에 들어가고, 컨테이너에 의해 관리가 되게 된다.

@Controller
public class MemberController {
    private final MemberService memberService;

    @Autowired
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }
    // 생성자에 @Autowired 어노테이션을 불여주면, 스프링 컨테이너에 있는 memberService 스프링이 연결해준다.
    // 위와 같은 작업이 가능한 전제 조건은 MemberService가 스프링 컨테이너에 의해 관리되고 있어야 한다는 점이다.
    // 때문에 해당 MemberService클래스 위에는 @Service 어노테이션을 붙여주어야 한다.
    // 일반적으로 @Service, @RestController, @Controller, @Repository 등의 어노테이션이 존재한다.
    // 기본적으로 @Component 라는 어노테이션을 통해 스프링 빈에 자동 등록이 되는데, @Controller, @Service, @Repository는 @Component를 포함하고 있기 때문에 해당 어노테이션을 통해서도 스프링 빈에 등록이 되게 된다..
    // 최상단에 public static void main을 실행하는 Application 클래스의 하위 구조에서 가능한다.
    // 또한 스프링 컨테이너에 등록되는 각 클래스들은 싱글턴 패턴을 취하여, 각 1개의 클래스들만 등록되어 프로젝트에서 공유된다. 이는 메모리를 절약해준다.

    /**
     * 스프링 빈을 등록하는 두 가지 방식
     *  빈(Bean)이란 ?
     *  1. 컴포넌트 스캔을 통한 자동 의존관계 설정 방식
     *  이는 앞서 설명하였던 것으로, 어노테이션 등을 사용하는 방식이다.
     *  2. 자바 코드를 통해 직업 스프링 빈을 등록하는 방식
     * */
}

생성자에 @Autowired 어노테이션을 불여주면, 스프링 컨테이너에 있는 memberService 스프링이 연결해준다.
위와 같은 작업이 가능한 전제 조건은 MemberService가 스프링 컨테이너에 의해 관리되고 있어야 한다는 점이다.
때문에 해당 MemberService클래스 위에는 @Service 어노테이션을 붙여주어야 한다.
일반적으로 @Service, @RestController, @Controller, @Entity, @Repository 등의 어노테이션이 존재한다.
즉 의존성은 주입받는 쪽에서는 생성자 함수에 @Autowired를 붙여주며, 의존성을 제공하는 클래스 위에는 각 클래스의 역할에 맞는 어노테이션을 붙여주면 된다. 

만일 동일한 클래스명으로 등록된 빈이 존재하는 경우에는 @Qualifier를 통해 의존 관계를 주입하여 줄 수 있다. 예를 들면 @Qualifier어노테이션의 인자에 명칭을 주어 @Autowired를 통해 가져올 때 해당 명칭을 동일하게 넣어 가져와주는 것이다.

@Component
@Qualifier("commonutil")
public class CommonUtil {
	

}
@Service
public class MemberController {
    @Autowired
    @Qualifier("commonutil")
    private CommonUtil commonUtil; 

}

@Configuration : 스프링 설정 정보를 관리하는 클래스임을 선언하는 어노테이션

@Bean : 의존성 주입을 위한 빈등록을 해주는 어노테이션 

@ComponentScan : 기본 패키지 경로를 설정해준 하위에서 @Controller, @Service, @Repository, @Component 어노테이션이 붙은 클래스를 자동으로 컨테이너에 등록하여 주는 어노테이션으로, 즉 빈을 등록할 범위를 설정해주는 어노테이션이라 할 수 있다.

@Component : 해당 어노테이션이 사용된 경우 @ComponentScan의 대상이 된다. @Controller, @Service, @Repository 어노테이션들이  @ComponentScan에 의해 등록될 수 있는 것은 해당 어노테이션들이 @Component를 상속받았기 때문이다.

@Autowired : 주입 대상이되는 bean을 컨테이너에 찾아 주입하는 어노테이션


자바 코드를 통해 직접 스프링 빈 등록 (config 파일 생성)

Application이 처음 시작되는 main함수가 있는 Application클래스와 같은 경로에 SpringConfig 클래스 파일을 생성하여 주고, 그 안에는 아래와 같이 작성하여 준다. 

@Configuration
public class SpringConfig {

    @Bean
    public MemberService memberService () {
        return new MemberService(memberRespository());
    }
    @Bean
    public MemberRespository memberRespository() {
        return new MemoryMemberRepository();
    }
}

아래와 같이 @ComponentScan을 사용한 경우 @Bean 등의 어노테이션을 통해 빈을 등록해주지 않아도, 자동으로 패키지 경로 하위에서 @Controller, @Service, @Repository, @Component 어노테이션들이 붙은 경우 빈으로 자동으로 등록하여 관리해준다.

 

@Configuration
@ComponentScan("com.mihee.oh")
public class SpringConfig {

    @Bean
    public MemberService memberService () {
        return new MemberService(memberRespository());
    }
    @Bean
    public MemberRespository memberRespository() {
        return new MemoryMemberRepository();
    }
}

/애플리케이션 컨텍스트와 빈 팩토리

 

[Spring] 애플리케이션 컨텍스트(Application Context)와 스프링의 싱글톤(Singleton)

이번에는 애플리케이션 컨텍스트에 대해 간단히 알아보도록 하겠습니다. 1. 애플리케이션 컨텍스트(Application Context) [ 애플리케이션 컨텍스트(Application Context)란? ] Spring에서는 빈의 생성과 관계

mangkyu.tistory.com

빈의 생성 및 설정 등의 제어를 담당하는 Ioc 컨테이너를 빈 팩토리(Bean Factory)라고 하며, 빈 팩토리를 상속받아 애플리케이션을 위해 필요한 추가적인 기능 설정을 할 수 있도록 한 것이 애플리케이션 컨텍스트(Application Context)이다. @Configuration 어노테이션은 애플리케이션 컨텍스트가 참고하는 설정정보의 하나이다. 즉 @Configuration 어노테이션이 이용된 클래스는 애플리케이션 설정 정보를 담고 있는 클래스임을 알 수 있다.

@Bean어노테이션은 스프링 빈으로 해당 클래스를 등록하여 주는 기능을 한다.

* 불가피한 데이터베이스 변경 등의 이유로 구현 클래스 변경이 필요한 경우에는 config 파일을 활용하는 것이 가장 효율적이다. 예를 들어 위의 설정에서 아래와 같이 변경해주면 간단하다.

@Configuration
public class SpringConfig {

    @Bean
    public MemberService memberService () {
        return new MemberService(memberRespository());
    }
    @Bean
    public MemberRespository memberRespository() {
        return new RdbMemberRepository();
    }
}

 

 

출처

https://www.boostcourse.org/web326/lecture/58970?isDesc=false 

 

반응형