@Autowired vs @RequiredArgsConstructor vs @Resource 차이점
by 무작정 개발이전에 국비 교육을 들을 때 의존성 주입을 하면 @Autowired 혹은 @Resource 이 2개의 어노테이션을 사용했었다.
최근에 의존성 주입을 할 때 위 2개의 어노테이션 말고 @RequiredArgsConstructor 가 더 실용적이라고 하여
이 3가지 어노테이션의 차이점에 대해 찾아보고 정리하고자 한다.
[ 학습할 3가지 어노테이션 ]
- @Resource
- @Autowired
- @RequiredArgsConstructor
시작하기 앞서 스프링 공식 문서에서는 생성자를 통한 의존성 주입 (DI)를 권장하고 있다.
1. DI (의존성 주입) 방법
먼저 객체 의존관계를 외부에서 넣어주는 것을 DI (Dependency Injection), 의존성 주입이라고 한다.
DI 방법으로는 총 3가지가 있다. 필드 주입, 생성자 주입, 메서드 주입이다.
지금까지는 필드 주입을 사용하였고, @Autowired 혹은 @Resource 어노테이션을 사용하였다.
그런데 @RequiredArgsConstructor는 필드 주입처럼 작성하지만, 사실은 생성자 주입을 하게 도와주는 어노테이션이다.
DI(의존성 주입)에 대해 자세히 보려면 이전 글 참조 -> [Spring 2.5] DI, IoC 란?
2. @Autowired vs @RequiredArgsConstructor vs @Resource
이 3가지 어노테이션을 일반적으로 @Controller가 선언된 클래스에 Service 빈을 주입할 때 많이 사용해서 컨트롤러 소스 일부분을
예시로 추가하였다.
(1) @RequiredArgsConstructor
- 밑의 소스는 컨트롤러 소스 일부분이다.
@RestController
@RequiredArgsConstructor
public class DictionaryApiController {
private final DictionaryService dictionaryService;
@RequestMapping(value = "/new/test", method = RequestMethod.GET)
public String getIndexListTest() {
dictionaryService.getIndexNameList();
return "내가 보이면 성공이다.";
}
@RequiredArgsConstructor의 특징은 다음과 같다.
- 이 어노테이션은 Lombok에서 지원하는 어노테이션이다.
- 필드 주입처럼 보이지만 @RequiredArgsConstructor를 사용하면 생성자로 의존성 주입을 한다.
- final 키워드가 붙은 필드에 대해 생성자를 만들어준다.
- 스프링 개발팀에서 생성자 주입을 사용할 것을 권장하는 이유는 한번 의존성 주입을 받은 객체는 프로그램이 끝날 때까지 변하지 않는 특징을 가지므로 불변성을 표시해주는 것이 좋기 때문이다. -> 객체의 불변성(Immutability) 보장
[ @RequiredArgsConstructor 특징 요약 ]
(1) 코드 변이에 대한 안전성
@RequiredArgsConstructor는 생성자 중에서 final 키워드가 붙은 주입에만 생성자를 만들어준다.
final이 붙어있기 때문에 인스턴스가 생성될 때 1번만 참조되므로 코드 변이의 걱정은 사라진다.
(2) 순환 참조에 대한 안전성
생성자 어노테이션을 사용할 경우에 순환 참조가 일어날 시 Exception이 발생하여 컴파일 중에 에러가 발생한다.
이를 통해 Test 단계에서 순환 참조를 파악하여 수정할 수 있다.
(2) @Autowired
- 밑의 소스는 컨트롤러 소스 일부분이다.
// 예전에 국비 교육에서 배웠던 방법
@Controller
public class BoardController {
@Autowired
private BoardService boardService;
...
}
// 생성자에 @Autowired를 써줘서 스프링이 연관된 객체를 스프링 컨테이너에 찾아서 넣어줌
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
@Autowired의 특징은 다음과 같다.
- Autowired는 필드 주입 방식의 의존성 관리 방법이다.
- Field, Setter Method, Constructor(생성자)에 사용 가능하다.
- 기본적으로 Type을 기준으로 의존성을 주입 (DI)
- 동일한 Type의 빈(Bean)이 여러 개 존재할 경우 기본적으로 참조 변수의 이름과 동일한 Bean을 찾아서 의존성을 주입한다.
- 이름을 기준으로 의존성 주입을 할 때 @Qualifier 어노테이션을 사용해서 DI 될 Bean을 지정
- 만약 동일한 Type의 Bean이 여러 개 존재할 경우에는 @Primary 어노테이션을 사용해서 의존성 주입이 될 Bean을 지정 가능하다.
[ @Autowired 단점 ]
(1) 단일 책임의 원칙 위반 가능성
(2) 코드 변이의 가능성
@RequiredArgsConstructor을 통한 생성자 주입 방식을 활용할 경우에는 final 옵션을 사용하기에 객체가 변질될 가능성이 배제된다.
But, @Autowired를 통한 필드 주입 방식은 final 옵션을 사용할 수 없기에 코드가 변질될 가능성이 존재한다.
이는 로직에 따라 큰 에러가 발생할 가능성이 있기 때문에 중요한 문제이다.
(3) 불확실한 참조
@Autowired는 DI가 타입(Type)이 같은 빈(Bean)이 발견되면 그냥 주입한다.
지금까지 의존성 주입이 간편했던 이유인데 이것이 문제가 되는 이유는 같은 Type의 다른 객체가 여러 개일 때 문제가 발생한다.
DI가 Type만 보고 내려주기에 서로 다른 A타입의 객체가 2개 존재한다면 @Autowired는 Error를 띄울 수밖에 없다.
(4) 순환 참조의 가능성
생성자를 통한 의존성 주입은 클래스가 순환 참조가 의심되면 런타임(RunTime)이 Exception을 발생시키기에 미리 코드의 문제점을 파악할 수 있다.
(3) @Resource
- 밑의 소스는 컨트롤러 소스 일부분이다.
@RestController("memberController")
@RequestMapping("/movie")
public class MemberController {
@Resource // 얘를 호출하면 MemberServiceImpl이 딸려들어옴 (의존성 주입)
private MemberService memberService;
//로그인 화면 - (완성)
@GetMapping("/login")
public ModelAndView login() throws Exception {
ModelAndView mav = new ModelAndView();
mav.setViewName("member/login");
return mav;
}
....
}
@Resource의 특징은 다음과 같다.
- Field, Setter Method에 사용 가능하다. (생성자에는 불가능)
- 기본적으로 참조 변수의 이름과 동일한 Bean이 존재하면 해당 Bean을 의존성 주입한다.
- name 속성을 사용해서 의존성 주입받을 Bean을 지정할 수 있다.
- name(이름)으로 Bean을 찾지 못하면 Type을 기준으로 의존성 주입을 한다.
- Java 9 이후로는 삭제되었다. (ex : java 11 버전을 사용하면 @Resource 사용 못함)
3. 추가 : Setter를 사용해서 의존성 주입을 하지 않는 이유
Setter를 통해 메서드로 의존성 주입을 하면 public으로 열려있기 때문에 다른 곳에서 해당 메서드를 통해 주입이 가능하다.
-> 즉, 호출하지 말아야 할 메서드를 호출하게 될 수도 있다.
의존 관계가 실행 중에 동적으로 변경되기 때문에 동적으로 변경되지 않도록 생성자를 통한 의존성 주입을 권장
Reference
'Back-End > SpringBoot' 카테고리의 다른 글
[Spring] @RequestMapping이란 그리고 동작 방식 (0) | 2022.12.14 |
---|---|
@Controller와 @RestController 차이점 (2) | 2022.11.03 |
[Spring boot] 프로젝트 패키지 구조 (0) | 2022.09.15 |
[Spring Boot] 스프링 부트에서 JSP 사용하기(JSP파싱) (1) | 2022.04.01 |
[Spring Boot] 스프링 부트 + MyBatis 게시판 (0) | 2022.03.30 |
블로그의 정보
무작정 개발
무작정 개발