https://chanho0912.tistory.com/8?category=866707
https://chanho0912.tistory.com/9?category=866707
위 두 포스팅에서 Dependency Injection과 Bean에 대해 간단하게 살펴보았다.
이번에는 실제 코드로 한번 Dependency Injection을 확인해보자.
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.samples.petclinic.owner;
import org.springframework.samples.petclinic.visit.VisitRepository;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import javax.validation.Valid;
import java.util.Collection;
import java.util.Map;
/**
* @author Juergen Hoeller
* @author Ken Krebs
* @author Arjen Poutsma
* @author Michael Isvy
*/
@Controller
class OwnerController {
private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm";
private final OwnerRepository owners;
private VisitRepository visits;
public OwnerController(OwnerRepository clinicService, VisitRepository visits) {
this.owners = clinicService;
this.visits = visits;
}
...
}
위 코드는 spring boot 프로젝트인 pet-clinic 코드의 owner controller를 참고하였다.
해당 코드는
https://github.com/spring-projects/spring-petclinic
에서 참고 가능하다.
우리가 살펴볼 부분은
private final OwnerRepository owners;
private VisitRepository visits;
public OwnerController(OwnerRepository clinicService, VisitRepository visits) {
this.owners = clinicService;
this.visits = visits;
}
이 부분이다.
보면 OwnerController의 생성자로 OwnerRepository와 VisitRepository를 주입받고 있다.
@Autowired를 생성자 위에 붙여서 생성자로 의존성을 주입받는 것을 표시했었는데, Spring 4.3 version부터 어떠한 class에 생성자가 하나뿐이고, 생성자로 주입받는 변수들이 Bean으로 등록되어 있다면 자동으로 주입을 해준다.
IOC container가 OwnerController를 생성할 때 해당 Bean들을 주입해준다고 생각하면 된다.
위와같이 생성자를 사용하지 않고 의존성을 주입받으려면
@Autowired
private OwnerRepository owners;
@Autowired
private VisitRepository visits;
// public OwnerController(OwnerRepository clinicService, VisitRepository visits) {
// this.owners = clinicService;
// this.visits = visits;
// }
위와 같이 생성자를 지우고, @Autowired Annotation을 활용하여 기존의 Bean들을 주입받아 사용할 수 있다.
혹은 Setter를 활용하여 주입받는 방법도 유효하다.
private OwnerRepository owners;
private VisitRepository visits;
@Autowired
public void setOwners(OwnerRepository owners) {
this.owners = owners;
}
@Autowired
public void setVisits(VisitRepository visits) {
this.visits = visits;
}
위와 같이 Setter method를 활용하여 기존의 Bean들을 주입받을 수도 있다. 이 경우 Set method에 @Autowired Annotation을 붙여주어야 한다.
위와 같은 여러 방법이 있지만, Spring에서 권장하는 방법은 생성자를 통한 의존성 주입인데 그 이유는
필수적으로 사용하는 Bean 없이는 생성되지 않도록, 강제할 수 있다.
즉 생성자로 의존성을 주입받으면 OwnerRepository가 정상적으로 작동하지 않거나, 존재하지 않으면 Controller를 생성할 수 없다.
반대로 @Autowired를 사용하거나 Setter를 사용하게 되면, 일단 IOC Container가 Controller를 생성할 수 있다.
(순환 참조가 발생하는 경우에는 생성자를 통한 주입을 받을 수 없다. 그런 경우가 아니면 일반적으로 생성자를 통한 주입이 권장된다 : A -> B 주입받는데, B -> A 주입받는 경우 서로 생성 불가)
위와 같은 안정성의 문제로 아마 생성자를 통한 주입을 권장하는 것 같다.
하지만 특별한 경우가 아니면 개발자의 방식이나 회사의 방식에 따르지 않을까 싶다. 저러한 방법들이 있구나 정도를 알아두면 좋을 것 같다.
*저의 글에 대한 피드백이나 지적은 언제나 환영합니다.
'Backend > Spring' 카테고리의 다른 글
[Spring] PSA란? (0) | 2021.06.24 |
---|---|
[Spring] AOP란? (1) | 2021.06.23 |
[Spring] IOC 컨테이너와 Bean이란? (0) | 2021.06.16 |
[Spring] IOC(Inversion Of Control), DI(Dependency Injection)이란? (0) | 2021.06.16 |
[Spring/SpringMVC] Dispatcher Servlet이란? (1) | 2021.06.15 |