개인 프로젝트 중 엑셀 파일을 다룰 일이 있었다. Apache POI 라이브러리를 활용하여 코딩을 시작할려하니 CSV
파일 처리에 대해 고려해야 했고 이를 POI로 해결하기엔 비효율적일 수 있어 잠시 보류 해야했다.
이를 위해 코드도 열려 있는 코드를 작성해야한다 생각했고, 유지보수가 용이할 수 있게 Controller
클래스가 구현체에 의존하지 않게 Service
인터페이스를 의존하게 하여 코드 확장 가능성을 열어 두었다.
의존성 주입의 종류로는 Constructor(생성자)
, Setter
, Field
가 있다.
@Controller
public class POIController{
private POIService poiSerivce;
@Autowired
public POIController(POIService poiService){
this.poiService = poiService;
}
}
@Controller
public class POIController{
private POIService poiSerivce;
@Autowired
public void setPoiController(POIService poiService){
this.poiService = poiService;
}
}
@Controller
public class POIController{
@Autowired
private POIService poiSerivce;
}
또한 lombok
라이브러리 @RequiredArgsConstructor
를 활용하여 생성자를 통해 의존성을 주입 받을 수 있다.
@Controller
@RequiredArgsConstructor
public class POIController{
//final
private final POIService poiSerivce;
}
스프링(Spring4.0 이상)은 생성자주입 방식을 권장하고 이처럼 3.Field
방식처럼 코드가 간결할 뿐만 아니라 생성자를 통해 의존성을 주입할 수 있게 해준다
하지만 field 주입은 권장하지 않기에 굉장히 이점이 많다 그리고 난 이 방법을 사용할거다
- 명확한 의존성 표현
- 불변성과 불변성 보장
- 테스트 용이성
- 순환 참조 방지
- 코드 품질 및 가독성
public interface POIService {
// 기타 등등
public void excelUpload();
}
@Service
public class POIServiceImplA implements POIService{
@Override
public void excelUpload(){
System.out.println("POI A를 호출");
//내부 로직
}
}
```java
@Service
public class POIServiceImplB implements POIService{
@Override
public void excelUpload(){
System.out.println("POI B를 호출");
// 내부 로직
}
}
앞서 말한거 처럼 구현체를 의존하지 않게 위와 같이 코드를 짜보았다고 가정하자
하지만 문제가 있는데
이처럼 POIService에 @RequiredArgsConstructor 어노테이션이 적용되지 않는걸 볼 수 있다
구현체가 하나가 있으면 문제가 생기지 않는데 두개 이상일 경우에는 A와 B 중 어느 클래스를 주입해야하는지 애매모호해진다
@Controller
public class POIController{
private POIService poiSerivce;
@Autowired
public void setPoiController(POIServiceA poiServiceA){
this.poiService = poiServiceA;
}
}
@Autowired를 사용하여 생성자의 파라미터를 지정하여 사용할 수 있지만 나는 @RequiredArgsConstructor로 충분히 가능할거 같았고 방법을 찾아 보았다.
말한거 처럼 @RequiredArgsConstructor를 사용하면 스프링은 어떤 클래스를 주입해야하는지 모른데 그래서 @Primary를 사용하여 문제를 해결하였다.
@Primary 어노테이션을 붙여주면 자동적으로 해당 빈이 선택된다. 주입 받을 때마다 모든 코드에 @Qualifier 어노테이션을 붙여줘야하는 Qualifier 방법보다 간단하다.
@Primary
@Service
public class POIServiceImplA implements POIService{
@Override
public void excelUpload(){
System.out.println("POI A를 호출");
// 내부 로직
}
}
정상적으로 출력이 되는 모습이다