Java Spring Boot 001-3 | Spring IoC, DI, Beans

Yunny.Log ·2022년 1월 21일
0

Spring Boot

목록 보기
9/80
post-thumbnail

1. Java Interface

(+) 이 부분에서 설명 어려워하는 분들 많을 것 같아서 인터페이스에 대한 개념 설명 필요할 듯

(ex) 소방차, 경찰차, 자가차 등 여러가지 자동차가 존재, 이때 자동차에 공통적인 기능이 존재할 것, 이 기능이 모든 종류의 자동차에 존재하도록 강제하고 싶을 때 interface에 자동차가 가져야할 공통적인 성질 정의 ,추상메소드 제공을 통해서 동일기능 수행하게 하는 것

  • 추상클래스, 인터페이스 잘 사용하는 것 중요
  • 인터페이스를 잘 사용하면 서로 다른 구현체가 같은 목적을 위해 동작하도록 만들기 가능
  • 사용하고자 하는 개체의 실제 자료형과 무관하게 동작하게 만들기 가능
  • 함수의 인자와 반환 값은 인터페이스를 활용할 수 있도록 하자
  • inputstream의 구현체가 많이 존재하는데, 이들은 다 inputstream의 기능을 가진다 => 즉 inputstream을 필요로 하는 기능엔 구분없이 사용 가능

2. IoC Container란

ioc 컨테이너 대한 설명 참고 출처 블로그

  • ioc : inversion of control : 제어의 반전

    기존에는 개발자가 프레임워크의 코드를 가져다가 썼지만, ioc에서는 프레임워크의 코드가 개발자의 코드를 가져다가 쓰는 것

=> 기존의 모든 제어를 클라이언트 코드가 가지도록 구현하던 것에서 기존 구조적 설계와 비교해, 프레임 워크가 제어를 나눠 가져가게 됨
=> 이로써 의존 관계의 방향이 달라지게 되는 것을 제어 반전이라고 함

  • ioc container
    => ioc를 구현하는 프레임워크로 객체를 관리하고 객체 생성 책임, 의존성 관리하는 컨테이너
    => ioc를 담당하는 컨테이너
    => 프레임워크를 기반으로 만든 애플리케이션이 작동을 할 때 개발자가 작성한 코드와 설정정보를 합쳐서 만들어져야 할 객체들을 직접 만들어주는 역할을 한다
    => 이 객체가 이런 역할 할거라고 정의해두면 생성자를 통해서 객체를 만들어서 직접적으로 배치해줌

  • 모든 의존성을 컨테이너 통해 받아오게 됨 -> 실수로 서로 다르게 구현 되는 경우 없음

  • 즉 ioc 컨테이너로 관리를 하게 되면 필요한 객체를 외부에서 생성해서 ioc 컨테이너로 객체를 주입시키는 것

전통적인 프로그래밍에서 흐름은 프로그래머가 작성한 프로그램이 외부 라이브러리의 코드를 호출해 이용합니다.(프로그래머 코드 -> 외부 호출)
하지만 제어 반전이 적용된 구조에서는 외부 라이브러리의 코드가 프로그래머가 작성한 코드를 호출 (외부 코드 -> 프로그래머 코드 호출)

3. Spring Bean과 DI

  • 스프링 ioc 컨테이너가 개발자가 작성한 코드설정정보를 합쳐서 만든 객체를 Bean이라고 부름

  • Bean은 스프링 ioc 컨테이너가 관리하는 객체라고 할 수 있음

  • 개발자가 비즈니스 로직 코드 작성

  • 로직 코드 작성하면서 다른 객체를 사용해야 하는 시점에서 ioc 컨테이너에서 이미 만들어져있던 bean 객체를 전달해줌
    => 개발자는 new로 선언돼있던 객체들 관리, 어떤 시점에서 만들어져있던 객체들을 신경써줄 필요가 없게 된다.

  • Spring에서 구현을 요구하는 부분들을 인터페이스로 정의

  • 이후 사용자가 정의한 구현체 Bean을 실제 서비스에서 사용하게 되는 것

ioc 컨테이너는 인터페이스 기반으로 작동을 하게 되는 것
interface로 구현된 구현체들을 데리고 dependency injection을 진행하게 된다

Dependency Injection (의존성 주입) 이란

ioc, di 아래 글 참고 블로그글

  • di : 의존성 주입
    => 하나의 객체 a가 다른 객체 b 를 의존해야 할 때
    => a의 코드 내부에서 b를 만들지 x
    => 외부의 ioc 컨테이너에서 b를 만들고 생성자, setter 메소드 등의 방식을 활용해
    => a의 내부로 주입시키는 것
  • 위와 같은 di 진행방식을 통해서 모듈 간의 결합을 낮춰서 수정이 발생했을 때 코드 변경지점을 최소화 할 수 있음

Inversion of control 개념 추가

(출처는 위와 동일!)
=> 프레임워크가 개발자의 코드를 호출하면서 프로그램의 흐름을 주도하는 것

일반적인 흐름

객체 a 생성 -> 내부에서 의존성 객체 b 생성 -> 의존성 객체 b 의 메소드를 호출
(ex) new를 통해 내부에서 객체 생성해서 사용하는 방식

class OwnerController {
    private OwnerRepository repository = new OwnerRepository();
}

=> 일반적인 흐름의 윗 코드 설명 :
1) OwnerController 라는 a 가 OwnerRepository 라는 b 를 필요로 함
2) a의 내부에 new 를 활용해서 b라는 객체를 생성

ioc 적용 흐름 :

  • 스프링에서는 모든 의존성 객체(Bean)을 스프링 컨테이너에서 직접 관리
  • 이 Bean을 필요로 하는 곳에 주입해줌

    객체 a,b 생성 -> 의존성 객체 b를 필요로 하는 곳에 b 주입 -> 이후 의존성 객체 b의 메소드를 호출

class OwnerController {
    private final OwnerRepository repository;

    public OwnerController(OwnerRepository repository) {
        this.repository = repository;
    }
}

=> ioc 흐름의 윗 코드 설명 :
1) OwnerController 이라는 a가 b를 필요로 할 때 생성자를 이용해서 외부에서 b를 호출해서 a 에 주입하는 중


4. 코드로 ioc 유무의 차이 이해하기

1. 일반적 interface 활용 코드(ioc x)

Ainterface.java (인터페이스)

package hello.hellospring;

public interface AInterface {
    void sayHello();
}

Acomponent.java (클래스)

package hello.hellospring;

public class Acomponent {
    private AInterface A;
    public Acomponent(AInterface A){
        this.A = A;
        //this는 현재 생성자 그 자체 가리키는 것
    }
    public void sayHello(){
        this.A.sayHello();
    }
}

static main 이 있는 곳

package hello.hellospring;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class HelloSpringApplication {

	public static void main(String[] args) {
		Acomponent acomp = new Acomponent(
				new AInterface(){
					@Override
					public void sayHello() {
						System.out.println("this is temporary interface");
					}
				}
		);
		acomp.sayHello();
		SpringApplication.run(HelloSpringApplication.class, args);

	}

}

-> 결과 :
=> 현재는 new 를 활용해서 필요한 인터페이스를 내부에 생성함


ioc 활용 시

  • Acomponent 클래스 위에 @Component 붙이게 되면 스프링 ioc 에서 관리하는 객체로 변하게 됨
  • 아래와 같이 @Component 붙이고 위의 코드 실행한다면

Parameter 0 of constructor in hello.hellospring.Acomponent required a bean of type 'hello.hellospring.AInterface' that could not be found.

라는 에러가 등장함 이유는 아래와 같은 것이다.

1) 이는 현재 Acomponent 가 @Component라는 annotaion 달리게 되면서 ioc의 관리를 받게 되었다
2) Acomponent는 Ainterface를 필요로 하는 객체다.
3) ioc의 관리에 들어가게 되면 a,b의 bean 객체가 미리 생성해놓고 (ioc가 얘네를 관리) -> a 가 b를 필요로 할 때 ioc 컨테이너는 bean객체에서 b를 데려다가 a에 주입시켜줌 (dependency injection) -> 이렇게 주입된 b를 a는 잘 사용함
의 단계로 활용이 되어야 한다.

즉 ioc는 bean 형태의 객체로 관리를 해야하는데 현재 Ainterface의 bean 객체가 존재하지 않는다는 것 (Ainterface 는 그 자체만 있고 얘를 implements한 다른 구현체들은 존재하지 않는 상태)

따라서 우리는 ioc를 고려해서 Ainterface를 implements 할 아이(bean)를 만들어주어야 함 - bean 형태로 만들어주려면 @Component 붙여주면 된다.

따라서 Ainterface를 bean 객체로 하나 생성해주자

package hello.hellospring;
import org.springframework.stereotype.Component;

@Component
public class AinterfaceImplements implements AInterface{
    @Override
    public void sayHello() {
        System.out.println("방가방가 I am Bean!");
    }
}

스프링 부트를 다루는 것은 Bean을 얼마나 적절히 잘 사용하는지에 관한 것

Spring에서 구현을 요구하는 부분들을 interface를 통해서 정의,
이후 사용자가 정의한 구현체 Bean을 실제 서비스에서 사용!

5. Spring과 Spring Boot의 차이

Bean <= 개발자의 코드 + 설정

1) Spring Framework

  • 스프링 프레임워크는 설정을 xml 파일로 만들어 주었다.
    (ex) 보안 설정 시 어떤 파일을 보안처리해야하는지 xml 로..
    => xml 작성, 다루는 일이 까다로워서 입문하는 것 어려움

  • JAVA Web Application (WAR 파일), 스스로 실행 불가
    => 실행을 위해 톰캣과 같은 웹 애플리케이션 서버 필요

  • 실행 시

    Web Application Server -> 스프링(WAR파일들)

2) Spring Boot

  • 설정이 Spring Boot Starter에 정의되어 있음

  • 톰캣과 같은 웹어플리케이션 서버 프로그램이 내장 , JAR의 형태로 실행 가능
    => JAR은 자바 명령어로 바로바로 실행 가능

  • 실행 시

    스프링부트(JAR파일)

  • Build a server that runs

0개의 댓글