스프링 부트 핵심 가이드 책을 통한 글 입니다.
기본적으로 java에서는 객체를 직접 생성하고 해당 객체의 의존성을 생성한 후 객체에서 제공하는 기능을 사용한다. 하지만 제어역전(Inversion of Control)을 특징으로 하는 스프링은 객체를 직접 생성하지 않고 스프링 컨테이너(Spring Container) 또는 IoC컨테이너(IoC Container)라고 불리는 컨테이너를 통해 객체 관리를 컨테이너에게 맞겨 객체를 관리하는데 이를 제어역전(IoC)라고 한다.
제어 역전을 통해 의존성 주입 및 관점 지향 프로그래밍이 가능하다.
의존성 주입(DI)은 제어 역전(IoC)의 방법 중 하나로, 사용할 객체를 직접 생성하지 않고 외부 컨테이너가 생성한 객체를 주입받아 사용하는 방식이다. 즉, 의존성 주입(Dependency Injection, DI)은 스프링 컨테이너에 의해 관리되는 빈(bean)을 통해, 객체를 직접 생성하지 않고 주입하여 사용하는 방식 이다.
@Controller, @Service, @Repository, @configuration와 같은 어노테이션은 모두 스테레오타입(stereotype) 어노테이션으로, **스프링 컨테이너에 빈(bean)으로 자동 등록된다.
@Bean은 @Configuration으로 선언된 클래스 내에 있는 메서드를 정의할 때 사용한다.Bean이 되며, default로 메서드 이름이 Bean의 이름이 된다.Stereotype의 클래스들을 탐지하고 Bean으로 등록한다.bean에 등록된다.
스프링에서는 @Autowired라는 어노테이션을 통해 의존성을 주입할 수 있는데, 스프링4.3 이후 생성자를 통해 의존성을 주입할 때 @Autowired 어노테이션을 생략할 수 있다. 보통 생성자나 setter 메서드를 통해 의존성을 주입받는다.
1) 생성자를 통한 의존성 주입
@RestController
public class DIController{
MyService myService;
@Autowired
public DIController(MyService myService){
this.myService = myService;
}
@GetMapping("/di/hello")
public String getHello(){
return myService.getHello();
}
}
MyService는 @Service 어노테이션 등을 통해 스프링 컨테이너에 빈으로 등록되어 있다고 가정하면, DIController 클래스는 생성자를 통해 myService에 해당 bean(MyService)을 주입받는다. DIController 클래스의 생성자에 @Autowired 어노테이션이 붙어 있으며, 이는 스프링 컨테이너가 DIController를 생성할 때 MyService 타입의 bean을 주입하도록 지시한다. Spring 공식 사이트에서는 이 방식을 추천한다.@Autowired 어노테이션을 생략할 수 있다.-> 소프트웨어 공학에서 공부했던 단일책임의 원리(클래스는 오직 하나의 책임을 가져야 한다는 원칙)과 관련된 것이라고 볼 수 있음.2) 필드 객체 선언을 통한 의존성 주입
@RestController
public class FieldInjectionController{
@Autowired
private MyService myService;
}
3) setter 메서드를 통한 의존성 주입
@RestController
public class SetterInjectionController{
MyService myService;
@Autowired
public void setMyService(MyService myService){
this.myService=myService;
}
}
setter 매서드를 통한 의존성 주입은 꼭 @Autowired 어노테이션을 붙여줘야한다.의존성은 클래스A가 클래스B를 사용할 때, 클래스B의 변경이 클래스A에 영향을 미치는 관계를 의미한다. 이러한 의존성은 상속, 인터페이스, import, 애노테이션 등등의 관계에서 일어난다.
new를 통해 생성하여 객체를 재사용한다는 점이 효율적이었지만, 공통된 부가기능에 대한 코드가 중복되고 반복된다는 점에서 효율적이지 못하였다. 아래의 예시코드로 예시를 들면, running...이라는 코드가 중복되었다고 할 수 있다. class baseball{
method hit(){
batting...
running...//중복
}
method steal(){
stop...
running...//중복
}
}
class soccer{
method goal(){
running...//중복
pass...
shot...
}
}
running... 이 부분을 AOP를 활용하여 모듈화 시키면, running...은 AOP에 의해 자동 실행된다.class baseball{
method hit(){
batting...
//running...은 AOP에 의해 자동 실행
}
method steal(){
stop...
//running...은 AOP에 의해 자동 실행
}
}
class soccer{
method goal(){
//running...은 AOP에 의해 자동 실행
pass...
shot...
}
}
