스프링 빈과 의존관계

김소희·2023년 4월 5일
1

스프링빈 등록하는 방법

스프링빈을 등록하는 방법은 2가지가 있다.
컴포넌트 스캔과 자동 의존관계 설정자바 코드로 직접 스프링 빈으로 등록하는 방법 둘 다 잘 알아야 한다.
실무에서는 주로 정형화된 컨트롤러, 서비스, 레포지토리 같은 코드는 컴포넌트 스캔을 사용하고, 정형화 되지 않거나, 특수한 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다.

1.컴포넌트 스캔과 자동 의존관계 설정

@Conponent 애너테이션이 있으면 스프링이 실행될 때 스프링 컨테이너에 스프링빈으로 자동 등록된다. 주의할 점은 main 메소드를 포함하는 패키지 내에 있는 @Conponent를 모두 찾아서 등록시키므로 다른 패키지에 @Conponent를 붙여도 등록되지 않을 것이다.(등록시키는 방법이 없진않지만 지금은 다루지 않겠다.)

@Controller, @Service, @Repository에 들어가보면 @Conponent를 포함하고 있기 때문에 클래스의 객체를 생성해서 스프링빈으로 등록하여 관리하게 된다.

생성자에 @Autowired 가 있으면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어준다.
생정자가 1개만 있으면 @Autowired를 생략할 수도 있다.
이렇게 객체 의존관계를 외부에서 넣어주는 것DI (Dependency Injection), 의존성 주입이라 한다.

package hello.hellospring.controller;

import hello.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller // @Controller 애너테이션 붙이기
public class MemberController {

	private final MemberService memberService;
		@Autowired // 생성자에도 @Autowired붙여주기
        public MemberController(MemberService memberService) {
        	this.memberService = memberService;
        }
}

@Service // 애너테이션
public class MemberService {

	private final MemberRepository memberRepository;
    
	@Autowired
	public MemberService(MemberRepository memberRepository) {
		this.memberRepository = memberRepository;
	}
}

@Repository // 애너테이션
public class MemoryMemberRepository implements MemberRepository {}

스프링은 스프링빈을 등록할때 기본적으로 싱글톤으로 등록한다 (유일하게 1개만 등록해서 공유한다) 따라서 같은 스프링빈이면 모두 같은 인스턴스다. 설정으로 싱글톤이 아니게 설정할 수 있지만, 특별한 경우를 제외하면 대부분 싱글톤을 사용한다.

2.자바코드로 직접 스프링빈 등록하기

config클래스를 생성한 후에 @Configuration 애너테이션을 붙이고
빈으로 등록할 생성자에 @Bean 애너테이션을 붙인다.
컨트롤러의 경우에는 컴포넌트 스캔을 사용해야하므로 Service나 Repository에만 주로 쓰인다.
연결이 필요한 경우 (의존관계 일 경우) 'new MemberService(memberRepository());' 처럼 매개변수에 메소드를 넣어준다.

import 생략

@Configuration
public class SpringConfig {

	@Bean
    public MemberService memberService() {
    	return new MemberService(memberRepository());
    }
    
    @Bean
    public MemberRepository memberRepository() {
    	return new MemoryMemberRepository();
    }
    
    

XML 문서로 설정하는 방식도 있지만 최근에는 실무에서 거의 사용하지 않는다.

DI방법

DI에는 필드주입, setter주입, 생성자주입이 있는데 의존관계가 실행중에 동적으로 변하는 경우는 거의 없으므로 생성자 주입을 권장한다.

@Autowired을 통한 DI는 스프링이 관리하는 객체에서만 동작하므로 스프링빈으로 등록하지 않고 내가 직접 생성한 객체에서는 동작하지 않는다 (내가 new로 생성해서 주입할수 없다.)
쉽게 말해서 @Service를 지우면 @Autowired가 동작하지 않는 것을 확인 할 수 있다.

생성자 주입방법

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

필드 주입방법

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

이렇게 작성하면 아마 IDE가 @Autowired에 물결표시가 뜨면서 Create constructor 메세지를 보여줄 것 이다. 필드 주입은 스프링이 실행될 때만 주입해주고 이후에 바꿀수 있는 방법이 없기 때문에 별로 좋지 않은 방법이기 때문에 경고를 띄우는 것이다.

Setter 주입

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

setter주입과 같은 경우에는 생성은 생성대로 되고 나중에 setter가 호출이 되어 들어오는 방식이다. 단점으로는 누군가가 맴버 컨트롤러를 호출했을때 public으로 열려있어야만 가능한데 MemberService를 주입한 이후에는 중간에 바꿔치기를 할 이유가 없음에도 노출이 되게되고 실수로 중간에 잘못 바뀌는 오류가 발생할 가능성이 아주 낮은 확률이겠지만 존재하게 된다.
호출하지 않아야 한 메소드가 호출되는 것 자체가 좋은 코드가 아니기 때문에 생성자 주입방법을 사용하는 것이 바람직하다.(실무에서도 생성자 주입을 사용한다.)

profile
백엔드 자바 개발자 소희의 노트

0개의 댓글