Spring - 객체 주입 직접생성(new) vs DI컨테이너

지니·2023년 8월 20일
0

spring

목록 보기
6/13

new로 인스턴스를 생성해서 사용하는것과 DI 컨테이너로 주입받는 방식의 차이점이 뭘까?

1. 개념설명

  • Spring Framework에서는 Dependency Injection (DI) 패턴을 사용하여 객체 간의 의존성을 관리한다.

  • 이 패턴을 사용하면, 객체를 직접 생성하는 대신 Spring 컨테이너에 의해 생성된 객체(빈)를 주입받아 사용할 수 있다. 이로 인해 코드는 더욱 유연해지고 테스트하기 쉬워진다.

2. 객체 인스턴스를 new 키워드로 직접 생성하는 방식과 DI로 주입받는 방식의 차이점

  • 객체 생성의 책임:
    new 키워드를 사용하면, 객체 생성의 책임이 해당 코드에 있다. 반면에 DI를 사용하면, 객체 생성의 책임이 Spring 컨테이너에 있다. 이로 인해 코드는 객체 생성에 대한 세부 사항을 알 필요가 없으며, 대신 인터페이스에 의존할 수 있다.

  • 테스트 용이성:
    new 키워드를 사용하면, 해당 객체와 강하게 결합되므로 테스트하기 어렵다. 반면에 DI를 사용하면, 테스트 시에 실제 객체 대신 모의 객체(mock object)를 주입할 수 있으므로 테스트하기 쉽다.

  • 유연성:
    new 키워드를 사용하면, 해당 코드는 특정 구현에 의존하게 된다. 반면에 DI를 사용하면, 코드는 인터페이스에 의존하므로 구현을 쉽게 변경할 수 있다.

  • 따라서, Spring Framework를 사용하는 경우에는 가능한 한 DI를 사용하는 것이 좋다. 그러나 모든 객체를 빈으로 만들 필요는 없다.
    예를 들어, 상태를 가지지 않는 유틸리티 클래스나, 도메인 객체와 같이 생명주기를 Spring 컨테이너가 관리할 필요가 없는 객체는 new 키워드를 사용하여 직접 생성할 수 있다.

3. 그럼 컬렉션 타입은 new로 생성해도 괜찮은가?

  • 내가 만든 클래스가 아닌 Java에서 사용가능한 Map, List, Set 같은 컬렉션 타입은 new를 통해 생성해도 사용해도 되는가?

  • HashMap, ArrayList와 같은 Java의 표준 컬렉션 클래스들은 상태를 가지지 않는 유틸리티 클래스나 도메인 객체와 같이 생명주기를 Spring 컨테이너가 관리할 필요가 없는 객체들이다. 이런 경우에는 new 키워드를 사용하여 직접 생성하는 것이 일반적이다.

4. 컬렉션은 메소드의 매게변수에 선언해서 그것을 메서드 내부에서 가져다 세팅하는것이 좋은가? 아니면 메서드 내부에서 new로 컬렉션 타입의 객체를 생성해서 사용하는게 좋은가?

  • 예시코드를 보자
// nameList에 값을 넣어서 save()메소드로 리스트의 값을 저장하는 컨트롤러 로직이다.
@ResponseBody
@GetMapping("/)
public String getPage(List<String> nameList) {
		
		nameList.add("data1");
		nameList.add("data2");
		userService.save(nameList);

		return "ok";
}
  • 이 경우에는 nameList를 메서드의 매개변수로 받는 것이 아니라, 메서드 내부에서 new ArrayList<>();를 사용하여 nameList를 생성하는 것이 더 적절하다.

  • 왜냐하면, nameListgetPage() 메서드 내부에서만 사용되며, 이 메서드의 사용자가 nameList를 제공할 필요가 없기 때문이다. 또한, nameList를 메서드의 매개변수로 받으면, 이 메서드의 사용자가 nameList의 상태에 대해 알아야 하므로 메서드의 사용성이 저하될 수 있다.

4-1. 따라서, 코드를 다음과 같이 수정하는 것이 좋다.

@ResponseBody
@GetMapping("/")
public String getPage() {
		// new가 보기싫어도 얘들은 이렇게 작성하는게 좋다고 한다.
    List<String> nameList = new ArrayList<>();
    nameList.add("data1");
    nameList.add("data2");
    userService.save(nameList);

    return "ok";
}
  • 이렇게 하면 getPage() 메서드는 nameList의 생성과 관리를 스스로 담당하며, 이 메서드의 사용자는 nameList에 대해 알 필요가 없다. 이로 인해 코드가 더 간결하고 명확해진다.

  • 컬렉션 타입은 new로 생성해도 괜찮은가? - 결론
    메서드 내부에서만 사용되는 컬렉션을 메서드의 매개변수로 받는 것은 일반적으로 권장되지 않는다. 이런 경우에는 메서드 내부에서 new 키워드를 사용하여 컬렉션을 직접 생성하는 것이 더 간결하고 명확하다. 또한, 이렇게 하면 메서드의 사용자는 메서드가 어떤 컬렉션을 사용하는지 알 필요가 없으므로 메서드의 사용성이 향상된다.

  • 따라서, 메서드 내부에서만 사용되는 컬렉션을 메서드의 매개변수로 받는 것은 일반적으로 좋지 않은 설계이다. 대신, 메서드 내부에서 new 키워드를 사용하여 컬렉션을 직접 생성하고 사용하는 것이 좋다.

5. 컬렉션 타입은 메서드 안에서 new로 많이 작성해도 괜찮은가? (성능이슈 체크)

  • ArrayList, HashMap과 같은 컬렉션 인스턴스를 new 키워드를 사용하여 생성하는 것은 일반적인 Java 프로그래밍의 일부이다.이러한 객체 생성은 JVM의 힙 메모리에 공간을 할당하는 작업을 포함하며, 객체가 더 이상 필요하지 않게 되면 가비지 컬렉터에 의해 자동으로 회수된다.

  • 일반적으로, 이러한 객체 생성과 가비지 컬렉션은 성능에 큰 영향을 미치지 않는다. JVM은 객체 생성과 가비지 컬렉션을 매우 효율적으로 처리하도록 설계되었으며, 대부분의 경우에는 이러한 작업이 애플리케이션의 성능에 미치는 영향을 거의 느끼지 못한다.

  • 그러나 매우 많은 수의 객체를 짧은 시간 동안 생성하거나, 매우 큰 객체를 생성하는 경우에는 성능에 영향을 미칠 수 있다. 이러한 경우에는 객체 풀링과 같은 기법을 사용하여 객체 생성의 비용을 줄이거나, 더 효율적인 자료 구조를 사용하여 메모리 사용량을 줄일 수 있다.

  • 따라서, ArrayList, HashMap과 같은 컬렉션 인스턴스를 new로 생성하는 것이 성능에 미치는 영향은 대부분의 경우에는 무시할 수 있을 정도이다. 그러나 특정 상황에서는 이러한 객체 생성이 성능에 영향을 미칠 수 있으므로, 성능이 중요한 애플리케이션에서는 적절한 성능 테스트와 최적화를 수행해 보는것이 좋다.

profile
탐구하는 Backend 개발자

0개의 댓글

관련 채용 정보