2023.08.27 - Spring 입문 (2주차)

mjjin·2023년 8월 27일
0

IoC(Inversion of Control)와 DI(Dependency Injection)

IoC : 소프트웨어의 제어권을 객체에서 컨테이너로 역전시키는 개념
DI : IoC를 구현하기 위한 방법 중 하나로 객체의 의존 관계를 컨테이너가 외부에서 주입해주는 방식

의존성

<의존성이 높은 코드>

public class Consumer {

    void eat() {
        Chicken chicken = new Chicken();
        chicken.eat();
    }

    public static void main(String[] args) {
        Consumer consumer = new Consumer();
        consumer.eat();
    }
}

class Chicken {
    public void eat() {
        System.out.println("치킨을 먹는다.");
    }
}

<Interface를 활용한 코드>

public class Consumer {

    void eat(Food food) {
        food.eat();
    }

    public static void main(String[] args) {
        Consumer consumer = new Consumer();
        consumer.eat(new Chicken());
        consumer.eat(new Pizza());
    }
}

interface Food {
    void eat();
}

class Chicken implements Food{
    @Override
    public void eat() {
        System.out.println("치킨을 먹는다.");
    }
}

class Pizza implements Food{
    @Override
    public void eat() {
        System.out.println("피자를 먹는다.");
    }
}

주입

여러 방법을 통해 필요로 하는 객체를 해당 객체에 전달

<필드에 직접 주입>

public class Consumer {

    Food food;

    void eat() {
        this.food.eat();
    }

    public static void main(String[] args) {
        Consumer consumer = new Consumer();
        consumer.food = new Chicken();
        consumer.eat();

        consumer.food = new Pizza();
        consumer.eat();
    }
}

interface Food {
    void eat();
}

class Chicken implements Food{
    @Override
    public void eat() {
        System.out.println("치킨을 먹는다.");
    }
}

class Pizza implements Food{
    @Override
    public void eat() {
        System.out.println("피자를 먹는다.");
    }
}

<메서드를 통한 주입>

public class Consumer {

    Food food;

    void eat() {
        this.food.eat();
    }

    public void setFood(Food food) {
        this.food = food;
    }

    public static void main(String[] args) {
        Consumer consumer = new Consumer();
        consumer.setFood(new Chicken());
        consumer.eat();

        consumer.setFood(new Pizza());
        consumer.eat();
    }
}

interface Food {
    void eat();
}

class Chicken implements Food{
    @Override
    public void eat() {
        System.out.println("치킨을 먹는다.");
    }
}

class Pizza implements Food{
    @Override
    public void eat() {
        System.out.println("피자를 먹는다.");
    }
}

<생성자를 통한 주입>

public class Consumer {

    Food food;

    public Consumer(Food food) {
        this.food = food;
    }

    void eat() {
        this.food.eat();
    }

    public static void main(String[] args) {
        Consumer consumer = new Consumer(new Chicken());
        consumer.eat();

        consumer = new Consumer(new Pizza());
        consumer.eat();
    }
}

interface Food {
    void eat();
}

class Chicken implements Food{
    @Override
    public void eat() {
        System.out.println("치킨을 먹는다.");
    }
}

class Pizza implements Food{
    @Override
    public void eat() {
        System.out.println("피자를 먹는다.");
    }
}

IoC Container와 Bean

Bean : Spring이 관리하는 객체
Spring IoC 컨테이너 : 'Bean'을 모아둔 컨테이너

Spring 'Bean' 등록 방법

  1. 'Bean'으로 등록하고자 하는 클래스 위에 @Component 을 달아준다.
@Component
public class MemoService { ... }
  1. Spring 서버가 뜰 때 IoC 컨테이너에 'Bean'을 저장해준다.
    • @Component가 설정된 클래스에 대해서 Spring이 해주는 일 확인하기
// 1. MemoService 객체 생성
MemoService memoService = new MemoService();

// 2. Spring IoC 컨테이너에 Bean (memoService) 저장
// memoService -> Spring IoC 컨테이너

Spring 'Bean' 이름 : 클래스의 앞글자만 소문자로 변경
public calss MemoService -> memoService

  1. Spring 서버가 뜰 때 @ComponentScan에 설정해 준 packages 위치와 하위 packages 들을 전부 확인하여
    @Component가 설정된 클래스들을 'Bean'으로 등록해준다.
@Configuration
@ComponentScan(basePackages = "com.sparta.memo")
class BeanConfig { ... }

Spring 'Bean' 사용 방법

  1. 필드 위에 @Autowired를 달아준다.
@Component
public class MemoService {
		
    @Autowired
    private MemoRepository memoRepository;
		
		// ...
}
  1. 'Bean'을 주입할 때 사용할 메서드 위에 @Autowired를 달아준다.
@Component
public class MemoService {

    private final MemoRepository memoRepository;

    @Autowired
    public MemoService(MemoRepository memoRepository) {
        this.memoRepository = memoRepository;
    }
		
		// ...
}
  • 객체의 불변성을 확보할 수 있기 때문에 일반적으로는 생성자를 사용하여 DI하는 것이 좋다.
  • set... Method를 만들고 @Autowired를 적용하여 DI 할 수도 있다.

0개의 댓글