본문 바로가기
Spring_inflearn/입문

[Spring] inflearn 스프링 입문 - 스프링 빈과 의존관계 2

by clolee 2022. 9. 13.

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

 

MemberService @Service, @Autowired 지우기

MemoryMemberRepository @Repository 삭제

실행 -> MemberService가 스프링 빈에 등록 안되어 있음. => 오류

 

컴포넌트 스캔 아닌 직접 등록하는 방법

SpringConfig 파일 만들기

hello-spring/src/main/java/hello/hellospring/SpringConfig.java

package hello.hellospring;

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();
	}
}

스프링이 뜰 때 @Configuration 읽고 @Bean 쓰여진 memberService 로직({
return new MemberService();
}) 호출해 스프링 빈에 등록

memberService 는 생성자에서 memberRepository를 넣어줘야 함

 

memberRepository 등록

MemberRepository - interface

MemoryMemberRepository - 구현체

 

hello-spring/src/main/java/hello/hellospring/SpringConfig.java

memberService, memberRepository 둘 다 스프링 빈에 등록,

스프링 빈에 등록되어있는 memberRepository를 memberService에 넣어줌

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();
	}
}
public class MemberService {
	private final MemberRepository memberRepository;

	public MemberService(MemberRepository memberRepository) {
		
		this.memberRepository = memberRepository;
	}
    ...
}

 

생성자를 통해서 memberService가 MemberController에 주입 : 생성자 주입 (권장) 스프링 컨테이너가 올라가고 세팅되는 시점에 주입되고 끝남. 그다음엔 변경 못하도록 막아버림

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;
    }
}

 

필드에 @Autowired : 필드 주입 (별로 안좋음)

@Autowired private MemberService memberService;

 

setter(setXXX) 에 @Autowired 넣어줌 : setter 주입 

단점 : 누군가가 MemberController 호출했을 때 public으로 열려있어야 함. 중간에 바꿀 일 없는데 노출되어있어 중간에 잘못 바꾸면 문제 생김

@Controller
public class MemberController {

    private  MemberService memberService;

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

 

정형화된 컨트롤러, 서비스, 리포지토리 같은 코드는 컴포넌트 스캔 사용

정형화되지 않거나, 구현 클래스를 변경해야 하면 (구현체로 MemoryMemberRepository 사용 => MemoryMemberRepository를 다른 Repository로 변경. MemoryMemberRepository를 데이터베이스에 실제 연결하는 Repository로 바꾸기. 이때 기존의 운영 중인 코드를 하나도 손대지 않고 바꿔치기하는 방법이 있음.)

구현체만 변경 ex) new MemoryMemberRepository() => new DbMemberRepository()

@Configuration
public class SpringConfig {

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

 

@Autowired 는 스프링이 관리하는 객체에서만 동작. 스프링 빈으로 등록되어 있지 않으면 동작하지 않음.

new 해서 내가 직접 생성한 객체에서도 @Autowired 가 동작하지 않음. 스프링 컨테이너에 올라가는 것들만 @Autowired 기능이 동작함.

댓글