📌 스프링 빈을 만드는 방법 2가지
스프링 컨테이너가 관리하는 객체를 스프링 빈이라고 한다.
스프링 빈으로 만들고, 스프링 컨테이너가 관리하도록 해보자.
스프링 빈을 만들려면 어떻게 해야 될까? 2가지 방법이 있다.
- @Component
- @Configuration + @Bean
1. @Component를 통해 Bean 등록하기
@RestController
public class DemoController {
@GetMapping(path = "/test")
public String demo() {
return "test";
}
}
// @RestController -> @Controller -> @Component 를 포함한다.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component // -> 스프링 빈으로 등록해줘!
public @interface Controller {
@AliasFor(annotation = Component.class)
String value() default "";
}
@Controller를 뜯어보면 @Component를 가지고 있고, 스프링 빈을 만드는 1번째 방법을 사용하고 있다.
@Component 어노테이션을 가지고 있는 클래스는 스프링 애플리케이션이 실행될 때 스프링이 빈으로 등록해준다.
스프링 애플리케이션을 실행하면 아래의 그림처럼 DemoController class의 객체인 빈이 생성되고 컨테이너 관리하에 존재하게 된다.
2. @Configuration + @Bean을 통해 Bean 등록하기
아래처럼 @Configuration이 붙어있는 클래스에서, @Bean이 붙어있는 메서드의 반환값이 빈으로 등록된다.
@Configuration
public class Config {
// 15 원시값은 Integer객체가 되어 빈으로 등록된다.
@Bean
public int age() {
return 15;
}
// Person 객체가 빈으로 등록된다.
@Bean
public Person person() {
return new Person("hun", 20);
}
}
또한 @Configuration을 뜯어보면 @Component 가 붙어있다. 즉, 이 Configuration 클래스도 객체로 생성되어 빈으로 등록된다.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
. . .
}
📌 Controller -> Service -> Repository에서 DI 구현하기
아래 클래스는 @RestController, @Service, @Repository를 붙여줌으로써 컨트롤러, 서비스, 레포지토리 계층으로 사용하겠다는 의미가 담겨있다.
@RestController
public class DemoController {
@Autowired // -> 필드 초기화할 객체가 필요한데 Spring님! 저에게 DemoService타입의 빈(객체)을 주세요!
DemoService demoService; // -> 필드 초기화를 해주지 않았다..
@GetMapping(path = "/test")
public String demo() {
String response = demoService.find();
return response;
}
}
@Service
public class DemoService {
@Autowired
DemoRepository demoRepository;
public String find() {
String data = demoRepository.find();
return data;
}
}
@Repository
public class DemoRepository {
public String find() {
return "TEST";
}
}
또한 3개 모두 내부에 @Component를 가지고 있기 때문에 스프링 컨테이너가 관리하는 빈으로 등록될 것이다.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
. . .
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
. . .
}
여기서 컨트롤러의 필드인 DemoService demoService필드를 보면 초기화를 해주지 않았다.
하지만 이미 DemoService라는 클래스는 @Service를 통해 빈으로 등록되어 있기 때문에, Spring이 DemoService 빈을 주입해 준다.
즉, 원래라면 DemoController가 new DemoService(); 를 통해 생성해줘야 했던 것을, Spring이 외부에서 주입하는 방식으로 DI를 구현한다.
이게 가능하기 위해서는 주입받아야 하는 곳에 @Autowired를 붙이면 된다.
@Autowired는 Spring에게 "필요한 객체를 주세요"라고 요청하는 것과 같다. 여기서는 "DemoService 타입의 빈을 주세요"라고 하는 것과 같다.
DemoService 또한 @Autowired를 통해 DemoRepository를 주입(DI) 받고 있다.
이제 애플리케이션을 실행시키고 localhost:8080/test라고 요청을 보내면 아래와 같이 응답이 오는 것을 확인할 수 있다.
'Spring' 카테고리의 다른 글
Entity vs DTO vs VO (0) | 2023.11.07 |
---|---|
[Spring] HTTP method (0) | 2023.11.06 |
[Spring] Controller 구현하기 (0) | 2023.11.02 |
[Spring] Controller, Service, Repository 3계층의 역할 (0) | 2023.10.31 |
[Spring] 의존성 주입과 제어의 역전 (0) | 2023.10.30 |