Constructor Injection, Lombok

Jieun Yang·2023년 10월 20일

Spring Boot

목록 보기
2/4
//package, import 생략

@Service
@Transactional
public class MemberService {

    @Autowired
    private MemberRepository memberRepository;
    
//이하 생략 

}

Field Injection

@Autowire로 spring이 spring bean에 등록되어 있는 MemberRepository를 인젝션해준다.

필드 주입의 단점?

테스트할 때 MemberRepository를 못 바꿈(필드도 private으로 되어있고..)

해결 방법?

setter Injection 사용하기




@Service
@Transactional
public class MemberService {

    private MemberRepository memberRepository;

    @Autowired
    public void setMemberRepository(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
    
...
}

Setter Injection

테스트 코드 작성 시 직접 메서드를 통해 주입 가능하다
가짜 MemberRepository같은 주입이 가능

단점?

런타임 시점에 누군가 코드를 바꿀 수 있다
보통 애플리케이션 로딩 시점에 세팅 조립이 다 끝난다. 그러니 중간에 누가 바꿀 일이 없음. 바뀔 수 있다는 것은 좋지 않다.

해결 방법?

Constructor Injection(생성자 인젝션) 사용하기




@Service
@Transactional
public class MemberService {

    private final MemberRepository memberRepository;

    @Autowired
    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
    
...
}

Constructor Injection

한 번 생성 시 완성되어버림. 중간에 set...() 해서 바꿀 수 없다
변경할 일이 없기 때문에 MemberRepository 필드는 final로 작성 권장


예를 들어, 테스트 케이스 작성 시 MemberService를 작성하는데

public stativ void main(String[] args) {
	MemberService memberService = new MemberService();
}

new MemberService()에서 컴파일 에러가 남. 직접 주입해줘야 한다.


@Service
@Transactional
public class MemberService {

    private final MemberRepository memberRepository;

    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
    
...
}

스프링에서는 생성자가 1개인 경우, @Autowired가 없어도 자동으로 인젝션해줌

여기서 Lombok을 적용시키자.


@AllArgsConstructor

@AllArgsConstructor 얘는

    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

이걸 직접 만들어준다.

이것보다 더 좋은 건 RequiredArgsConstructor가 있다.
final에 있는 필드만 가지고 생성자를 만들어준다.


@RequiredArgsConstructor

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class MemberService {

    private final MemberRepository memberRepository;


처음과 비교해보면

//package, import 생략

@Service
@Transactional
public class MemberService {

    @Autowired
    private MemberRepository memberRepository;
    
//이하 생략 

}
  1. 생성자가 1개이므로 @Autowired 생략 가능
  2. 생성자는 한 번 완성하면 다음 변경할 일이 없기 때문에 final 작성
  3. @RequiredArgsConstructor 어노테이션 추가, 자동으로 final 필드를 생성자로 만들어줌



MemberRepository 클래스도 이렇게 적용이 가능하다.

기존 코드

@Repository
public class MemberRepository {

    @PersistenceContext
    private EntityManager em;
    
    //이하 생략
}

우선 생성자 주입을 해본다.

@Repository
public class MemberRepository {

    @Autowired
    private EntityManager em;

    public MemberRepository(EntityManager em) {
        this.em = em;
    }
    
    //이하 생략
}
  1. @Autowired는 지울 수 있다. Spring Data JPA가 @Autowired를 지원해준다.
  2. 기존 생성자 주입 코드는 삭제, @RequiredArgsConstructor 를 추가해준다.
  3. EntityManager 필드를 final로 작성해준다.


변경 코드

@Repository
@RequiredArgsConstructor
public class MemberRepository {

    private final EntityManager em;
    
    //이하 생략
}

참고로 EntityManager는 @Autowired로는 안 되고, @PersistenceContext 표준 어노테이션이 있어야 인젝션이 가능하다.
그러나 Spring Data JPA부터 @Autowired도 인젝션이 가능하도록 지원해준다.
추후에는 Spring 기본 라이브러리에서도 @Autowired도 인젝션이 가능하도록 지원할 예정이라고 한다.

0개의 댓글