이 글은 인프런에서 김영한 님의 "스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술"을 수강 후 개인적으로 공부한 내용을 정리한 게시글입니다. 잘못된 점이나 부족한 부분이 있다면 언제든 지적 부탁드립니다.
빈(Bean)이란 스프링 컨테이너에 의해 재사용 가능한 소프트웨어 컴포넌트이다.
즉 스프링 컨테이너에 의하여 생성되고 관리하는 자바 객체를 뜻하며, 하나 이상의 빈(Bean)을 관리한다.
- Spring Framework에서는
ApplicationContext.getBean()
등의 메서드로 직접 자바 객체를 가져올 수 있다.- IntelliJ 에서는 Bean 인 경우 아래 사진처럼 왼쪽에 아이콘으로 표시된다.
어노테이션이 붙어있는 클래스
를 자동으로 인지한다. @Component
어노테이션이 붙어있다면, 스프링이 자동으로 인지할 수 있게 된다.Bean Configuration File에 직접 Bean을 등록
하면 스프링이 인지할 수 있게 된다.
@Component
어노테이션이 있으면 스프링 빈으로 자동 등록된다.
@Component
를 포함하는 다음 애노테이션도 스프링 빈으로 자동 등록된다.
@Controller
@Service
@Repository
Spring 프로젝트에서 (프로젝트명)Application class를 @SpringBootApplication
어노테이션이 붙어있음을 확인할 수 있다.
이를 정의한 곳을 확인해보면
@ComponentScan
어노테이션이 붙어 있음을 확인할 수 있다.
이 어노테이션은 어느 지점부터 컴포넌트를 찾아보라고 알려주는 것
이다. 즉, 이 어노테이션을 사용한 @SpringBootApplication
어노테이션이 PlaylistPackApplication 클래스에 붙어있으므로 이 클래스의 하위 모든 패키지를 훑어보면서 @Component
어노테이션을 활용한 모든 클래스를 찾고, Bean으로 등록한다.
객체 의존 관계를 외부에서 넣어주는 것
- 의존성 주입은 반드시 Bean으로 등록된 객체들 끼리만 가능하다. ( 컨테이너에 Bean을 등록되어 있지 않은 객체는 의존성 주입을 해주지 않음)
- 생성자에 @Autowired 를 사용하면 객체 생성 시점에 스프링 컨테이너에서 해당 스프링 빈을 찾아서 주입한다.
코드가 간결하다
하지만, 클래스 외부에서 접근이 불가능해 테스트하기 어렵다는 단점이 있다.
프레임워크에 의존적이고 객체지향적으로 좋지 않다.
@Service
public class StationFieldService {
@Autowired
private StationRepository stationRepository;
public String sayHi() {
return stationRepository.sayHi();
}
}
변경 가능성이 있는 의존 관계에 사용한다.
생성자 호출 이후에 필드 변수에 변경이 일어나야 하므로, stationRepository 변수에 final 제어자를 붙일 수 없다.
@Service
public class StationSetterService {
private StationRepository stationRepository;
@Autowired
public void setStationRepository(StationRepository stationRepository) {
this.stationRepository = stationRepository;
}
public String sayHi() {
return stationRepository.sayHi();
}
}
생성자를 호출할 때 딱 1번만 호출되기 때문에 stationRepository 변수를 final로 관리할 수 있다.
생성자 주입 사용 시, 생성자가 1개인 경우 @Autowired를 생략할 수 있다.
@Service
public class StationConstructorService {
private final StationRepository stationRepository;
@Autowired
public StationConstructorService(final StationRepository stationRepository) {
this.stationRepository = stationRepository;
}
public String sayHi() {
return stationRepository.sayHi();
}
}
순환참조를 방지할 수 있고 final로 선언하여 불변성을 보장할 수 있으며 테스트에 용이한
생성자 주입을 권장
한다
package hello.hellospring.controller;
import hello.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
참고: 스프링은 스프링 컨테이너에 스프링 빈을 등록할 때, 기본으로
싱글톤
으로 등록한다(유일하게 하나만 등록
해서 공유한다) 따라서 같은 스프링 빈이면 모두 같은 인스턴스다. 설정으로 싱글톤이 아니게 설정할 수 있지만,
특별한 경우를 제외하면 대부분 싱글톤을 사용한다.
@Configuration
을 이용하면 Spring Project 에서의 Configuration 역할을 하는 Class를 지정할 수 있다.@Bean
어노테이션을 사용해주면 간단하게 Bean을 등록할 수 있다.package hello.hellospring;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;
import hello.hellospring.service.MemberService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean
public MemberService memberService() {
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}