본문 바로가기
항해99

[WIL] 3주차

by yeaseul912 2022. 7. 31.
728x90

시간이 너무 빠르다..

벌써 프로그래밍 심화주차이다.

Spring의 핵심에 대해 배워보도록 하자.!

Spring Module

출처 : https://programming.vip/docs/a-brief-introduction-to-spring-and-ioc-containers-and-bean-configuration.html

-- 목차 --
Inversion of Control (IoC)
Bean
Dependency Injection (DI)

Inversion of Control ( IoC )

객체의 생성부터 소멸까지 생성주기 관리를 스프링 컨테이너가 맡는 것.

제어권이 컨테이너로 넘어가기 되어 제어권의 흐림이 바뀌었다는 뜻으로 IoC라고 함.

 

스프링 컨테이너 (IoC 컨테이너)

스프링에서 쓰이는 여러 객체들을 생성, 관리하는 객체

Bean이라는 인스턴스 형태로 관리

 

Bean

스프링 컨테이너에 의해서 인스턴스화되어 조립되거나 관리되는 객체

(일반 객체와 차이점은 없고, 스프링 컨테이너에 의해 만들어진 객체를 스프링빈이라고 부를 뿐이다)

 

Bean 으로 등록하는 방법

1. Component Scan (Component Annotation)

  • SpringBoot Project 에서 @SpringBootApplication 어노테이션이 @ComponentScan 어노테이션을 포함하고 있다.
  • SpringBootConfiguration 어노테이션은 @ComponentScan 와 @EnableAutoConfiguration 를 포함
  • 최초에 @ComponenetScan으로 Bean 등록 후, @EnableAutoConfiguration으로 추가적인 Bean들을 읽어서 등록
  • @ComponentScan : 해당 패키지에서 @Component 어노테이션을 가진 Bean들을 스캔해서 등록
  • @EnableAutoConfiguration : Bean을 등록하는 자바 설정 파일. spring factories 내부에 여러 Configuration들이 있고, 조건에 따라 Bean 등록
  • @Repository, @Service, @Controller, @Configuration : @Component 라는 meta 어노테이션을 사용한 어노테이션으로 Component 어노테이션

2. JAVA 설정 파일 (Bean & Configuration Annotation)

초기 스프링에서 빈은 xml로 된 스프링 설정파일을 통해 이루어졌다.

현재는 @Configuration 어노테이션을 클래스 선언부에 추가하여 설정 클래스를 만들거나

특정 타입을 리턴하는 메서드에 @Bean 어노테이션을 붙여 자동으로 해당 타입의 빈 객체가 생성되도록 할 수 있다.

 

@Bean에 이름을 지정하는 방법

1. 이름을 명시하지 않은 경우

@Component : 소문자로 시작하는 클래스이름이 자동으로 사용됨.

@Bean : 소문자로 시작하는 메서드이름이 자동으로 사용됨.

 

2. 이름을 명시 한 경우

@Component : @Component("이름")과 같이 사용.

@Bean : @Bean(name="이름")과 같이 사용.

 

@Primary를 @Bean이나 @Componenet앞에 붙여 객체 생성의 우선권을 부여하거나

@Qualifier 와 @Autowired 함께 사용하여 Bean의 이름이 같은 객체를 찾을 수 있다.

// @Bean 이름 명시
@Bean(name="sample")
...

// 이름명시 및 객체 생성 우선권 부여
@Bean(name="sample2")
@Primary
...

// @Component 이름 명시
@Component("example")
....

// sample 이라는 Bean 가져오기
@Autowired
@Qualifier("sample")
....
 meta annotation ? 
Java5에 추가된 기능으로 어노테이션을 선언할 때 사용하는 어노테이션
Q. @Qualifier와 @Primary 중 객체 생성의 우선권이 부여된 것은?!
정답 : @Qualifier!

DI ( Dependency Injection 의존성 주입 )

어떤 객체가 사용하는 객체를 직접 생성하는 것이 아니라 주입하는 방법

IoC 컨테이너에서 관리 되고 있는 객체를 사용( 객체를 사용한다 == 객체의 기능에 의존한다 )

객체간의 결합이 느슨해진다 -> 관리 포인트가 줄어든다.

(객체를 조립한다 -> 조립형 컴퓨터 -> 레고 ㅋㅋ)

public class understandDI{

	public static void main(String[] args){
    	// 강한 결합, 날짜를 구하기 위해 Date 클래스에 의존
    	Date date = new Date();
    }
    
    public static void getDate(Date d){
    	// 약한 결합
    	Date date = d;
    }
    
    public static void memberuse1(){
    	// 강한 결합 : 직접 생성
    	Member m1 = new Member();
    }
    
    public static void memberUse2(Member m){
    	// 약한 결합 : 생성된 것을 주입 받음 (DI)
        // 이미 만들어져 있는 것을 주입 하기 때문에
        // 만들어 질지 안만들어 질지 걱정 할 필요 X
	Member m2 = m;
    }
}

 

의존성 주입 방법

 1. 필드 주입 (@Autowired)

  • Filed, Setter, Constructor 등 다양한 곳에 사용 할 수 있지만, Bean으로 등록되어 있지 않으면 Error가 발생.
  • 가장 많이 사용되방법이지만 최근에는 아래와 같은 문제점으로 사용하지 않는다.
    • 불변성을 허용하지 않는다 : final 선언을 통해 불변성을 확보할 수 없다.
    • 단일 책임의 원칙 위반 : 하나의 클래스가 많은 책임을 떠안게 된다.
    • DI 컨테이너의 결합성이 높다 : Field Injection을 사용하면 필요한 의존성을 가진 클래스를 곧바로 인스턴스화 시킬 수 없기 때문에 테스트 등의 상황에서 불편할 수 있다.
    • 의존성이 가려진다 : 의존성 주입을 한 특정 클래스가 생성되어 사용된다는 것은 그 안에 주입된 의존성들에 대한 부분도 책임을 가지고 동작해야 한다. 하지만 Filed Injection을 사용하면 이러한 부분들이 가려져 의존성에 대한 완벽한 파악이 힘들다.
  • 순환참조 방지가 불가능하다.
@Service
public class ExampleService {
    // 순환참조
    @Autowired 
    private PracticeService practiceService;
}
@Service
public class PracticeService {
    // 순환 참조
    @Autowired
    private ExampleService exampleService;
}

2. 수정자 주입 ( Setter Injection )

  • setter 함수를 사용하는 방법. setter함수에 @Autowired 어노테이션 명시
  • 선택적인 의존성을 선언할 때에 유용한 방식
  • @Autowired를 사용하면 아무런 오류 없이 정상 구동이 되지만, 순환 참조되는 메서드 실행 시 오류와 함께 종료된다.
  • 세팅 후 개발자가 접근 할 수 있다.
B b = new B();
A a = new A();
a.setB(b);
@Service
public class PracticeService {
    private ExampleService exampleService;
    // setter에 @Autowired
    @Autowired
    public void setExampleService(ExampleService exampleService){
        this.exampleService = exampleService;
    }	
}

 3. 생성자 주입 (Constructor Injection )

  • 필수 의존성 주입에 유용
  • @RequiredArgsConstructor 사용가능
  • 생성자 주입 방법은 먼저 Bean을 생성하지 않고, 생성자의 인자에 사용되는 Bean을 찾거나 Bean factories에서 만든다.
  • 객체 생성 시점에 Bean을 주입하기 때문에 서로 참조하는 객체가 생성되지 않은 상태에서 그 빈을 참조하기 때문에 오류가 발생한다.
  • 세팅 후 주입한 것은 변경 불가, 런타임시(프로그램 실행 중) 동적으로 의존 관계가 변경되는 경우는 없기 때문에 권장하는 방법.
B b = new B();
A a = new A(b);
@Service
public class MemberService {
 
    private MemberRepository memberRepository;
    
    @Autowired
    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
}
@RequiredArgsConstructor
@Service
public class MemberService {
 
    private final MemberRepository memberRepository;
}

테스트 코드 작성 편리

DI의 핵심은 관리되는 클래스가 DI 컨테이너에 의존성이 없어야 한다는 것.

독립적으로 인스턴스화 가능한 POJO(Plain Old Java Object) 이어야 한다.

DI 컨테이너를 사용하지 않고서도 단위 테스트에서 인스턴스화 할 수 있어야 한다.

 

불변성 : final

한번 주입받은 Reference 가 다른 Reference로 바뀌지 않도록 보장하기 위함.

 

Singleton Pattern ?
Spring Framework의 특징
객체를 생성 할 때 하나만 생성하게 해서 JVM의 메모리 사용을 최소화
같은 처리를 하나의 객체가 처리하게 하여 동시성 처리나 동작의 편의성을 제공
IoC 와 DI가 핵심
마치며..

DI, IoC, Bean에 대해 더 명확하게 알 수 있는 시간이었다.

한주동안 너무 많은 내용들이 쏟아져 나와서 정리할게 산더미 같지만 이렇게 넓게 배우고 서서히 깊게 파헤쳐 나가는 것도 좋은 것같다.

좀더 부지런해져서 하루동안 배운걸 하루안에 정리 할수 있으면 얼마나 좋을까 싶기도 하다.

또 키워드를 주고 바로 실전처럼 투입시키는것도 상당히 빠르게 전체 내용을 훑어볼 수 있게 해준다.

다음주에는 시큐리티와 OAuth2를 뽀갤것이다.!

 

 

Reference

[스프링부트] Bean 객체를 등록하는 두 가지 방법(@Component, @Bean)

[Spring] 필드주입 -> 생성자 주입방식으로 변경

[SpringBoot] IoC(제어의 역전)와 DI(의존성 주입)

[Spring] Meta Annotation 이란?(@Target, @Retention)

[Java] Meta Annotation 메타 어노테이션

반응형

'항해99' 카테고리의 다른 글

[TIL] 항해 22일차  (0) 2022.08.02
[TIL] 항해 21일차  (0) 2022.08.01
[TIL] 항해 19일차  (0) 2022.07.29
[TIL] 항해 18일차  (0) 2022.07.28
CRUD 와 HTTP Method  (0) 2022.07.26

댓글