[Spring] 빈(Bean)과 의존성 주입 방법

clean·2024년 2월 22일

Spring 입문 강의

목록 보기
3/6
post-thumbnail

이 포스트는 백기선님의 예제로 배우는 스프링 입문을 듣고 정리한 내용입니다.

Bean을 등록하는 방법

Bean을 등록하는 방법에는 크게 두가지가 있다.

  • 컴포넌트 스캔
  • xml 또는 자바 설정 파일을 통해 직접 Bean을 등록

컴포넌트 스캔

스프링은 특정 범위 전체를 컴포넌트 스캔하여 @Component 어노테이션이 붙은 클래스의 인스턴스를 만들어 Bean으로 등록한다.

@Component말고도 컴포넌트 스캔의 대상이 되는 어노테이션은 여러개가 있는데 예를 들어 아래의 어노테이션들이 대표적이다.

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

등등..

이것들이 컴포넌트 스캔의 대상이 되는 이유는, 내부 구현을 보면 이 어노테이션들도 @Component이 붙어있기 때문이다.

Controller.class (@Controller 파일)

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.stereotype;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component // ⭐️여기에 Controller 어노테이션이 붙어있다!
public @interface Controller {
    @AliasFor(
        annotation = Component.class
    )
    String value() default "";
}

그러면 컴포넌트 스캔을 하는 범위는 어떻게 되는 것일까?
바로 @ComponentScan 어노테이션이 붙은 class 파일부터 하위 패키지를 모두 스캔한다.

스프링 부트 프로젝트를 만들면 ~~Application.java라는 파일이 생기고 해당 파일의 클래스 위에는 @SpringBootApplication라는 어노테이션이 붙어 있다.

이 어노테이션 파일을 열어보면

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
) // ⭐️ @ComponentScan 어노테이션
public @interface SpringBootApplication {
    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    Class<?>[] exclude() default {};
    // .. 생략
}

@SpringBootApplicatin 어노테이션에도 @ComponentScan 어노테이션이 붙어있는 것을 확인할 수 있다.
따라서 스프링부트 프로젝트를 만들면 컴포넌트 스캔의 범위는~~Application.java의 하위 패키지 전체가 된다.

또, @Component 어노테이션이 붙지 않아도, Repository와 같은 특정한 인터페이스를 구현하는 클래스인 경우 빈으로 등록된다.

xml 또는 자바 설정 파일에서 직접 등록

이는 xml 설정 파일 또는 자바 설정 파일을 수정하여 등록하는 방법인데, 요즘은 자바 설정 파일을 더 많이 쓴다.
이 글에서는 자바 설정 파일로 등록하는 방법에 대해서만 알아보려고 한다.

우선 Bean으로 등록해줄 샘플 Controller Class를 하나 만들었다.

SampleController.java

package org.springframework.samples.petclinic.sample;

import org.springframework.stereotype.Controller;

@Controller
public class SampleController {
}

그리고 자바 설정 파일을 만들어줬다.

SampleConfig.java

package org.springframework.samples.petclinic.sample;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SampleConfig {
	@Bean
	public SampleController sampleController() {
		 return new SampleController();
	}
}

이렇게 @Bean 어노테이션을 달아주고, 해당 클래스의 인스턴스를 리턴하는 메소드를 만들어주면 빈으로 등록된다. 따라서 기존 SampleController 위에 있는 @Controller 어노테이션을 떼더라도 빈으로 잘 등록이 된다.

package org.springframework.samples.petclinic.sample;

import org.springframework.stereotype.Controller;

public class SampleController { // @Controller 지움
}

Bean을 꺼내 쓰는 방법

앞선 포스트에서 봤던 applicationContext.getBean()을 통해 직접 꺼내쓰는 방법 말고도, @Autowired 와 같은 어노테이션을 통해 의존성을 주입하여 빈을 사용하는 방법도 존재한다.

아래에서는 @Autowired를 통한 의존성 주입 방법을 알아보고자 한다.

@Autowired로 의존성을 주입하는 방법에는 3가지가 있다.

  • 생성자 주입
  • 필드 주입
  • setter 주입

1. 생성자 주입

생성자 주입은 생성자 메소드 위에 @Autowired 어노테이션을 달아서 의존성 주입을 하는 방식이다.

	private final OwnerRepository owners;
    
	@Autowired
	public OwnerController(OwnerRepository clinicService) {
		this.owners = clinicService;

	}

그런데 스프링 4.3부터 @Autowired를 붙이지 않고도 자동으로 생성자 주입을 할 수 있는 기능이 추가되었다.
아래 두 조건을 만족한다면 @Autowired 어노테이션 없이도 생성자 주입이 가능하다.

  • 어떤 클래스에 생성자가 한 개이다.
  • 그 생성자를 주입받는 래퍼런스 변수들이 빈으로 등록돼있다.

2. 필드 주입

필드 주입은 생성자 주입을 할 인스턴스 변수 위에 @Autowired를 붙여 의존성 주입을 하는 방법이다.

	private OwnerRepository owners;
    
	@Autowired
	private OwnerRepository owners;

3. setter 주입

세번째 방법은 setter 주입으로, setter 메소드 위에 @Autowired 어노테이션을 붙여서 구현할 수 있다.

	private OwnerRepository owners;
    
	@Autowired
	public void setOwners(OwnerRepository owners) {
		this.owners = owners;
	}

Reference

profile
블로그 이전하려고 합니다! 👉 https://onfonf.tistory.com 🍀

0개의 댓글