ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 생성자 주입(Constructor Injection)을 권장하는 이유
    Java 2023. 11. 20. 22:52

    개요

    스프링에서 의존성 주입(DI : Dependency Injection)하는 방법에는 크게 3가지가 있다.

    생성자 주입(Constructor Injection), 필드 주입(Field Injection), 수정자 주입(Setter Injection)으로 각각의 차이점과
    왜 생성자 주입을 사용해야하는지 정리해보고자 한다.

     

    의존성 주입 : 필요한 객체를 직접 생성한는 것이 아닌 외부로부터 객체를 받아서 사용하는 것으로 코드의 결합도를 낮추고 재사용성을 증가시킨다.

     

    생성자 주입(Constructor Injection)

    @Controller
    Public class TestController() {
    	TestService testService;
        
        @Autowired //단일 생성자이기 때문에 @Autowired 생략이 가능하다.
        public TestController(TestService testService) {
        	this.testService = testService;
        }
    }

     

     

    Spring에서 자동으로 Bean을 생성할 때, 생성자 파라미터에 맞는 타입의 Bean을 찾아서 의존성을 주입시켜준다.

    즉, Spring이 TestController Bean을 생성할 때, 생성자의 TestService타입에 맞는 Bean을 찾고 주입 시킨다.

    위의 코드는 단일 생성자이기 때문에 @Autowired를 생략해도 되지만, 생성자가 2개 이상인 경우,
    @Autowired 어노테이션을 붙여줘야한다.

     

    만약 같은 타입의 Bean이 여러개인 경우, @Qualifier를 통해 클래스명이나 지정한 Bean의 이름으로 가져올 수 있다.

    그리고 생성자 주입은 다른 방식의 주입과 다르게 필드를 final 키워드를 사용할  수 있다. 

     

    final 키워드 : final은 변수, 필드, 메서드, 클래스 등에 사용되는 키워드로, 사용된 곳에서 변경이 불가능하게 만듭니다.

     

     

    필드 주입(Field Injection)

    필드에 @Autowired만 붙여주면 자동으로 의존성 주입이 된다.

    사용법이 가장 편리한 방법이다.

    @Controller
    Public class TestController() {
        @Autowired
        TestService testService;
        
    }

    Spring에서 자동으로 TestService타입의 Bean을 주입시켜준다.

    위와 마찬가지로 만약 같은 타입의 Bean이 있다면 @Qualifier나 @Resource를 통해 이름으로 특정해서 주입할 수 있다.

     

    수정자 주입(Setter Injection)

    setter메서드에 @AutoWired를 붙인다.

    @Controller
    Public class TestController() {
        
        private TestService testService;
        
        @Autowired
        public void setTestService(TestService testService) {
        	this.testService = testService; 
        }
    }

     

    생성자 주입(Constructor Injection)의 장점

    그렇다면 왜 생성자를 통한 주입이 추천될까?

     

    1) 순환 참조 방지

    A객체는 B를 참조하고 B객체는 A를 참조하는 경우를 말한다.

    즉, 객체가 서로 참조하고 있는 경우이다.

    @Component
    public class Hello{
      @Autowired
      World world;  //World객체를 참조한다.
    
      public void method1() {
          world.method2();
      }
    }
    
    --------------------------------
    
    @Component
    public class World{
      @Autowired
      Hello hello; //Hello객체를 참조한다.
    
      public void method2() {
          hello.method1();
      }	
    }

    위와 같이 서로를 참조하고 있기 때문에

    실행시키면 잘 구동이 되다가 method1 함수를 호출하는 순간에 순환참조로 인해 StackOverflowError가 터지게 된다.

    즉, 메서드가 실행 시점 전까지 순환 참조가 있더라도 알 수 없다.

    반면, 생성자 주입을 만들게 된다면

    @Component
    public class Hello{
      World world;
    
      public Hello(World world) {
        this.world = world;
      }
    
      public void method1() {
        world.method2();
      }
    }
    
    -------------------------------------
    
    @Component
    public class World{
      Hello hello;
    
      public World(Hello hello) {
        this.hello = hello;
      }
    
      public void method2() {
        hello.method1();
      }	
    }

     

    이런식으로 처음부터 순환참조가 되고 있음을 알려준다.

    https://yaboong.github.io/spring/2019/08/29/why-field-injection-is-bad/

    인텔리제이의 경우는 위와같이 알려준다.

     

    2) 객체의 불변성

    위에서 언급했듯, 생성자를 통한 주입 방법만 final키워드를 사용할 수 있다.

    final 키워드를 사용해서 다른 곳에서 객체의 값을 바꾸지 못하도록 한다. 

     

    3) 테스트 코드 작성 용이

    생성자 주입을 사용하면 테스트 코드를 좀 더 편하게 작성할 수 있다.

    독립적으로 인스턴스화가 가능한 POJO(Plain Old Java Object)를 사용하면,

    DI컨테이너 없이도 의존성을 주입하여 사용할 수 있기 때문에 유지보수와 테스트 코드 작성 시 이점이 있다.

     

    POJO : "Plain Old Java Object"의 약어로, 간단한 자바 객체를 나타낸다.  POJO는 특정 프레임워크나 환경에 의존하지 않고, 순수한 자바 클래스를 지칭한다.

    POJO 기반의 코드는 프레임워크에 대한 의존성이 적어 유지보수와 테스트가 용이하다는 장점을 가지고 있다.

     


    참고자료

    https://dev-coco.tistory.com/70

    https://jackjeong.tistory.com/entry/Spring-%EC%83%9D%EC%84%B1%EC%9E%90-%EC%A3%BC%EC%9E%85-vs-%ED%95%84%EB%93%9C-%EC%A3%BC%EC%9E%85-Autowired

    https://yeonyeon.tistory.com/220

    https://n1tjrgns.tistory.com/230

    'Java' 카테고리의 다른 글

    객체지향 5원칙 SOLID  (1) 2023.11.23
    @Transactional이란 무엇인가  (0) 2023.11.22
    Early Return  (0) 2023.11.18
    JVM  (0) 2023.11.16
    Token인증 방식(JWT)과 Session인증 방식  (0) 2023.11.13
Designed by Tistory.