컴포넌트 스캔, 의존관계 자동 주입

2022. 9. 25. 13:25자바 & Spring

스프링 컨테이너

스프링 컨테이너를 이용해 객체를 스프링 빈으로 등록하고 컨테이너에서 스프링 빈을 찾아 사용할 수 있다.

스프링 컨테이너는 다음과 같은 이점을 제공해줌으로써 개발자가  객체 지향적인 개발을 할 수 있게 도와준다. 

 

의존관계 주입 (DI)

  • 컨테이너가 의존관계를 자동으로 주입

제어의 역전 (IoC)

  • 객체는 자신의 로직만 실행하고 프로그램의 제어흐름을 외부(스프링 컨테이너) 에서 실행.

싱글톤 패턴

  • 객체를 빈으로 등록해 찾아 사용할 수 있어 싱글톤 패턴을 보장해준다.

 

스프링 컨테이너를 만드는 방법

 

1) XML 기반으로 생성

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="memberService" class="studyhello.projectbuildname.member.MemberServiceImpl">
        <constructor-arg name="memberRepository" ref="memberRepository" />
    </bean>

    <bean id="memberRepository" class="studyhello.projectbuildname.member.MemoryMemberRepository" />

    <bean id="orderService" class="studyhello.projectbuildname.order.OrderServiceImpl">
        <constructor-arg name="memberRepository" ref="memberRepository" />
        <constructor-arg name="discountPolicy" ref="discountPolicy" />
    </bean>

    <bean id="discountPolicy" class="studyhello.projectbuildname.discount.RateDiscountPolicy" />
</beans>

XML 파일에 beans 태그로 설정, bean 태그를 이용해 스프링 빈을 등록할 수 있다.

bean 태그의 속성값인 id로 빈 이름, class 로 구현 클래스를 지정해줄 수 있다.

이는 @Configuration 으로 설정 파일을 만드는 것과 큰 차이가 없다. 

 

 

2) 어노테이션 기반의 자바 설정 클래스

@Configuration 을 붙인 AppConfig 클래스

ApplicationContext 의 구현체가AppConfig 클래스를 설정 정보로 활용한다.

 

스프링 컨테이너를 보통 ApplicationContext, BeanFactory 로 구분하곤 하는데 주로 ApplicationContext를 사용한다.

AppConfig 클래스를 구성 정보로 지정해 스프링은 이를 바탕으로 컨테이너를 생성한다.

 

위처럼 스프링 빈을 등록할 때 자바 코드의 @Bean, 아니면 XML의 bean 태그를 통해 등록할 스프링 빈을 우리가 지정해주었다.

하지만 빈의 개수가 많아진다면, 이렇게 설정 정보에 일일이 등록하기는 귀찮을 것이다.

 


컴포넌트 스캔(Component Scan)

  • 스프링이 설정 정보가 없어도 자동으로 스프링 빈을 등록해주는 기능이다.
  • 의존관계를 자동으로 대입해주는 @Autowired도 제공.
  • AppConfig 클래스에서 @Bean으로 빈으로 등록할 모든 클래스를 나열해줄 필요 없이, 빈으로 등록할 클래스에 @Component 를 붙여주면 됨.
  • @Component 가 아니더라도 이를 포함하는 어노테이션이 있다면 성립.

 

컴포넌트 스캔 추가 대상

  • @Controller
  • @Repository
  • @Service
  • @Configuration

해당 어노테이션 모두 @Component 를 포함하고 있다.

 

 

@Configuration
@ComponentScan( 
	excludeFilters = @Filter(type = FilterType.ANNOTATION, 
    classes = Configuration.class))
public class AppConfig {

}
  • @Component 가 붙은 클래스를 스캔해 스프링 빈으로 등록.

 

@Component 특성

  • @Component 가 붙은 클래스를 스캔, 스프링 빈으로 등록.
  • 빈 이름은 기본적으로 클래스명을 사용. 앞 글자는 소문자이다.
  • @Component 속성으로 빈 이름을 직접 지정해줄 수 있다.
  • 컴포넌트 스캔을 할 때 하위 패키지들 모두가 자동으로 컴포넌트 스캔의 대상이 된다.

클라이언트에서 설정 정보로 AppConfig를 넘겨주고, ApplicationContext의 구현체인 AnnotationConfigApplicationContext에서 ac.getBean()으로 스프링 빈을 불러오는 것은 동일하다.

public class MemberApp {
    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

        MemberService memberService = ac.getBean("memberService", MemberService.class);
    }
}

 

 

필터 (@Filter)

@ComponentScan 의 속성으로 @Filter 를 추가해 컴포넌트 스캔 대상을 직접 추가하거나, 제외할 수 있다.

 

includeFilters : 컴포넌트 스캔 대상을 추가로 지정.

excludeFilters : 컴포턴트 스캔에서 제외할 대상을 지정.

 

@IncludeComponent
public class A {

}

@ExcludeComponent
public class B {

}

 

다음과 같이 어노테이션을 통해 컴포넌트 스캔 대상을 추가 지정, 제외할 수 있음

A 클래스를 스캔 대상에 추가, B 클래스를 제외

@Configuration
@ComponentScan(
    includeFilters = @Filter(type = FilterType.ANNOTATION, classes = IncludeComponent.class),
    excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = ExcludeComponent.class)
)
static class AppConfig {
}

 


의존관계 자동 주입

스프링컨테이너는 우리가 지정한 클래스의 객체에 의존관계를 자동으로 주입해준다.

의존관계 주입의 종류로는 3가지가 있다.

  • 생성자 주입
  • Setter 주입
  • Field 주입.

그 중에서 생성자 주입을 사용하는 것이 좋다. 최근 DI는 대부분 생성자 주입을 사용하는 추세이다.

 

why?

  • 대부분의 의존관계 주입은 한번 일어나면 어플리케이션이 종료될 때까지 변경할 일이 거의 없음. (불변 객체)
  • 수정자 주입을 사용하면 setter 함수를 만들어야 하는데, 이를 통해 외부에서 변경할 수 있기에 위험!
  • 생성자 주입은 객체를 생성할 때 딱 한번만 호출되므로 불변하게 설계할 수 있다.
  • 의존관계 누락을 방지할 수 있음.

생성자 주입을 사용하면 필드에 final을 붙여 Null Point Exception도 컴파일 시점에서 막아준다. 이처럼 값이 설정되지 않는 문제도 해결할 수 있음.

 

 

Autowired 를 통한 생성자 주입

  • @Autowired는 의존관계를 자동으로 주입해준다. 의존 관계를 직접 명시해줄 필요 X
  • 컨테이너에서 자동으로 해당 스프링 빈을 찾아 주입한다.
  • 타입이 같은 빈을 찾아서 주입

 

@RequiredArgsConstructor

롬복 라이브러리가 제공하는 기능으로 final 이 붙은 필드나 @NotNull 이 붙은 필드를 모아 생성자를 자동으로 만들어준다.

이는 @Autowired가 붙은 생성자를 만들지 않고도 간단하게 의존성을 주입해줌.(final, @NotNull 이 붙은 필드만!)

 

 

 

 

 

 

 

 

 

 

 

@RestController :

컴포넌트 스캔 - 스프링 빈으로 등록되게 함.

 

@RequiredArgsConstructor :

final 키워드가 붙은 commentService, userService,

boardService에 자동으로 의존관계를 주입해준다.

 

flow

  • 어플리케이션 실행.
  • 컴포넌트 스캔의 대상이 되어 BoardController가 스프링 빈으로 등록됨.  BoardController 는 스프링 빈으로 등록되었기 때문에 싱글톤을 보장한다. (하나의 객체만 반환.)
  • final 키워드가 붙은 필드 3개는 컨테이너가 의존성을 자동 주입, 어플리케이션이 끝날 때까지 불변한다.

의존관계 주입을 사용할 때는 어플리케이션 시작 ~ 종료 시점까지 불변하게 설계하는 것이 중요!

 

 

BoardController 의 세 필드 UserService, BoardService, CommentService 에는 @Service 가 붙는다.

@Service -> @Component 를 포함해 컴포넌트 스캔 대상이 된다.

 

Controller, Service, Repository 세 계층으로 분리해서 사용하더라도 스프링 컨테이너가 객체를 알아서 관리.

빈으로 등록해 자동으로 의존성을 주입해주고, 컴포넌트 스캔을 통해 빈으로 등록, 싱글톤을 보장해준다.

따라서 개발하기 매우 편리하다.

'자바 & Spring' 카테고리의 다른 글

JDBC(Java Database Connectivity)  (0) 2022.11.02
빈 생명주기 콜백  (0) 2022.10.26
싱글톤(singleton) 패턴  (0) 2022.09.24
Spring 특징과 장점  (0) 2022.09.17
JUnit 단위 테스트  (0) 2022.09.07