개발자/workflow 리팩토링 프로젝트(SpringBoot,JPA,MySQL)

♣[WF/Spring] 의존성 주입(생성자주입/필드주입/수정자주입)/JPA에서 Lombok 이용한 의존성 주입

GoGo개발 2023. 2. 22. 16:53
의존성 주입을 하는 이유

 

의존성 주입은 필요한 객체를 직접 생성하는 것이 아닌 외부로부터 객체를 받아 사용하는 것이다
이를 통해 객체간의 결합도를 줄이고 코드의 재활용성을 높일 수 있다.
@Autowired 는 Spring에게 의존성을 주입하는 지시자 역할로 쓰인다.

객체 지향 프로그래밍에서 클래스간에 의존성이 있다는 것은 클래스간에 의존관계가 있다는 것을 뜻한다.
클래스 간에 의존관계가 있다는 것은 한 클래스가 바뀔 때 다른 클래스가 영향을 받는다는것을 뜬한다.

 

DI(의존성 주입)란 외부에서 두 객체 간의 관계를 결정해주는 디자인 패턴으로, 인터페이스를 사이에 둬서 클래스 레벨에서는 의존관계가 고정되지 않도록 하고 런타임 시에 관계를 동적으로 주입하여 유연성을 확보하고 결합도를 낮출 수 있게 해준다.

 

service / repository 관계에서는 service에 repository를 주입해 repository에서 변경이생겨도 service는 repository를 외부에서 주입받기때문에 service코드의 변경은 필요하지 않게 되는 것이다.

 

의존성 주입의 이유는 아래 블로그를 참고하자(매우 자세하니 꼭 보도록)

https://kotlinworld.com/64

 

의존성 주입이란 무엇이며 왜 필요한가?

목표 의존성 주입이 무엇인지 이해한다. 의존성 주입이 왜 필요한지 이해한다. 의존성 주입이란? 의존성 주입이란 클래스간 의존성을 클래스 외부에서 주입하는 것을 뜻한다. 더 자세하게는 의

kotlinworld.com

 

 

생성자 주입(Constructor Injection) 

 

생성자 주입은 생성자를 통해 의존 관계를 주입하는 방법이다

 

@Service
public class UserService {

    private final UserRepository userRepository;
    private final MemberService memberService;

    @Autowired
    public UserService(UserRepository userRepository, MemberService memberService) {
        this.userRepository = userRepository;
        this.memberService = memberService;
    }
    
}

생성자 주입은 생성자의 호출 시점에 1회 호출 되는 것이 보장된다. 그렇기 때문에 주입받은 객체가 변하지 않거나, 반드시 객체의 주입이 필요한 경우에 강제하기 위해 사용할 수 있다.  생성자가 1개만 있을 경우에 @Autowired를 생략해도 주입이 가능하다. 필드 객체에 final 키워드를 사용할 수 있다.

 

final 로 선언된 레퍼런스타입 변수는 반드시 선언과 함께 초기화가 되어야 하므로 setter 주입시에는 의존관계 주입을 받을 필드에 final 을 선언할 수 없다.

 

수정자 주입(Setter 주입, Setter Injection) 

 

수정자 주입은 필드 값을 변경하는 Setter를 통해서 의존 관계를 주입하는 방법이다. Setter 주입은 생성자 주입과 다르게 주입받는 객체가 변경될 가능성이 있는 경우에 사용한다. (실제로 변경이 필요한 경우는 극히 드물다.)

Setter 메소드에 @Autowired 어노테이션을 붙이는 방법이다
수정자 주입을 사용하면 setXXX 메서드를 public으로 열어두어야 하기 때문에 언제 어디서든 변경이 가능하다.

 

@Service
public class UserService {

    private UserRepository userRepository;
    private MemberService memberService;

    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Autowired
    public void setMemberService(MemberService memberService) {
        this.memberService = memberService;
    }
}

 

@Autowired로 주입할 대상이 없는 경우에는 오류가 발생한다. 위의 예제에서는 XXX 빈이 존재하지 않을 경우에 오류가 발생하는 것이다. 주입할 대상이 없어도 동작하도록 하려면 @Autowired(required = false)를 통해 설정할 수 있다.

 

 

필드 주입(Field Injection)

 

필드 주입(Field Injection)은 필드에 바로 의존 관계를 주입하는 방법이다. IntelliJ에서 필드 인젝션을 사용하면 Field injection is not recommended이라는 경고 문구가 발생한다.

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

 

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;
    @Autowired
    private MemberService memberService;

}

필드 주입을 이용하면 코드가 간결해져서 과거에 상당히 많이 이용되었던 주입 방법이다. 하지만 필드 주입은 외부에서 접근이 불가능하다는 단점이 존재하는데, 테스트 코드의 중요성이 부각됨에 따라 필드의 객체를 수정할 수 없는 필드 주입은 거의 사용되지 않게 되었다. 또한 필드 주입은 반드시 DI 프레임워크가 존재해야 하므로 반드시 사용을 지양해야 한다. 그렇기에 애플리케이션의 실제 코드와 무관한 테스트 코드나 설정을 위해 불가피한 경우에만 이용하도록 하자.

 

 

JPA에서 Lombok 라이브러리와 결합한 생성자 주입
Lombok이란 어노테이션 기반으로 코드를 자동완성 해주는 라이브러리이다. Lombok을 이용하면 Getter나 Setter, 생성자 등을 자동완성 시킬 수 있어서 개발자의 생산성을 높여준다.

어노테이션을 이용해서 간단하게 생성자 주입이 가능하다는 것!

 

@RequiredArgsConstructor

: final이나 @NonNull 인 필드 값만 파라미터로 받는 생성자를 만들어 준다.

 

@RequiredArgsConstrutor 을 이용하여 생성자 주입

@Service
@RequiredArgsConstructor
public class EmployeeService {
   private final EmployeeRepository employeeRepository;
   private final DeptService deptService;

 

어노테이션을 사용하지 않았을 경우 생성자 주입을 하게 되면 아래와 같다

 

@Service
@RequiredArgsConstructor
public class EmployeeService {
   private final EmployeeRepository employeeRepository;
   private final DeptService deptService;
   
      @Service
    public class BannerServiceImpl implements BannerService {
    
        private EmployeeRepository employeeRepository;
    
        private DeptService deptService;
    
        @Autowired
        public BannerServiceImpl(EmployeeRepository employeeRepository, private DeptService deptService) {
            this.employeeRepository = employeeRepository;
            this.deptService = deptService;
        }
        ..

 

@NoArgsConstructor

: 파라미터가 없는 기본생성자를 생성

 

@AllArgsConstrutor

: 모든 필드 값을 파라미터로 받는 생성자를 만듦

 

 

의존성 주입 이유, 테스트코드 등

https://mangkyu.tistory.com/125

 

[Spring] 다양한 의존성 주입 방법과 생성자 주입을 사용해야 하는 이유 - (2/2)

Spring 프레임워크의 핵심 기술 중 하나가 바로 DI(Dependency Injection, 의존성 주입)이다. Spring 프레임워크와 같은 DI 프레임워크를 이용하면 다양한 의존성 주입을 이용하는 방법이 있는데, 각각의 방

mangkyu.tistory.com

 

참고 롬복

https://velog.io/@developerjun0615/Spring-RequiredArgsConstructor-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%9C-%EC%83%9D%EC%84%B1%EC%9E%90-%EC%A3%BC%EC%9E%85

 

[Spring] @RequiredArgsConstructor 어노테이션을 사용한 "생성자 주입"

의존성주입의 종류로는 Constructor(생성자),Setter,Field 타입이 있다.Constructor(생성자)Setter3.Field생성자주입의 단점은 위의 Constructor(생성자) 코드처럼 생성자를 만들기 번거롭다는 것이다. 하지만 이

velog.io

 

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

 

스프링 - 생성자 주입을 사용해야 하는 이유, 필드인젝션이 좋지 않은 이유

개요 Dependency Injection (의존관계 주입) 이란 Setter Based Injection (수정자를 통한 주입) Constructor based Injection (생성자를 통한 주입) 스프링에서 사용할 수 있는 DI 방법 세가지 생성자 주입을 이용한 순

yaboong.github.io