안녕하세요!

지난 시간에 @Autowired라는 어노테이션을 통해 의존관계를 주입해 봤는데요! 하다 보면서 드는 생각은 어차피 의존관계 주입할 필드는 다 final을 쓸 거고, 다 생성자 만들어서 @Autowired 해줄 건데 엄청 반복적이면서 코드 길이만 늘리는 작업인 것 같아요.

저만 이런 생각을 한 것은 아닌가 봐요! 다른 엄청 똑똑한 개발자들이 이를 더욱더 간단하게 만들어줄 엄청난 기능을 만들어냈는데요. 바로 롬복이라는 것입니다!

(Lombok Project (고추..인가?))

롬복을 사용하면서 어떻게 더 간단하게 작업을 할 수 있게 되는지  알아봅시다!

👉이전 글 보러가기


롬복 초기설정

롬복은 기본 기능이 아닌 외부 라이브러리이기 때문에 설정을 해 줄 게 있습니다. 물론 우리는 일정 부분 이미 되어있지만 어떤 설정들이 롬복 설정인지확인해 봅시다.

Gradle 설정

build.gradle로 들어가 줍시다!

설정을 보게 되면 아래 두 부분이 롬복과 관련된 설정입니다.

...
configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}
...
dependencies {
	...
    compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'
    
    // 이 부분은 추가로 작성
    testCompileOnly 'org.projectlombok:lombok'
    testAnnotationProcessor 'org.projectlombok:lombok'
    // 여기까지
	...
}
...

우리가 프로젝트를 생성하면서 롬복 기능을 추가했던 것을 기억하실 분이 아마 있을 것입니다. 그래서 추가가 되어 있고, test에서도 롬복을 사용하기 위해 주석 사이에 있는 저 두줄도 추가로 입력해 주세요.

그리고 아래 사진과 같이 우측 위에 있는 코끼리를 클릭해 주세요!

Plugin 설정

그리고 플러그인을 하나 설치해줘야 합니다. Ctrl+Alt+S를 눌러 설정창에 들어오신 후 왼쪽 메뉴들 중 Plugins에 들어옵시다.

Marketplace에서 Lombok을 검색하신 후 Install 해주시면 됩니다.

IntelliJ 설정

 마지막으로 하나 더 설정해 줄게 남았습니다. 현재 이 Settings창의 왼쪽에 아래 사진과 같은 경로로 들어와 줍니다.

그리고 오른쪽 부분 맨 위 Enable annotation processing을 체크해 주시고 OK!

그 후 IntelliJ를 한번 껐다가 켜봅시다.


@RequiredArgsConstructor 적용

이제 한번 써봐야겠죠? 저희가 의존성 주입을 했던 MemberServiceImpl, OrderServiceImpl에서 의존성 주입을 더 간단하게 만들어봅시다.

package com.naver.shopping.order;
 
import com.naver.shopping.member.Member;
import com.naver.shopping.member.MemberRepository;
import com.naver.shopping.discount.DiscountPolicy;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
 
@Component
@RequiredArgsConstructor // <-- 추가됨
public class OrderServiceImpl implements OrderService {
    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;
    
    // 생성자 사라짐
 
    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        Member member = memberRepository.findById(memberId);
        int discountPrice = discountPolicy.discount(member, itemPrice);
        return new Order(memberId, itemName, itemPrice, discountPrice);
    }
 
    public MemberRepository getMemberRepository() {
        return memberRepository;
    }
}

(MemberServiceImpl은 직접 한번 적용해 보세요!)

@RequiredArgsConstructor 어노테이션 하나를 썼다고 이렇게나 간결해지다니!! rgsConstructor를 쓰게 되면 final이 붙은 필드는 롬복이 자동으로 생성자를 만들어주기 때문에 저희가 굳이 추가하지 않아도 됩니다.


@Getter와 @Setter

얘들은 이름 그대로 저희가 Getter와 Setter를 코드에 추가하지 않아도 롬복이 자동으로 만들어주기 때문에 얘도 코드가 엄청 간결해질 수 있습니다.

Member 클래스에서 한번 적용해볼까 죠?

<이전>

package com.naver.shopping.member;
 
public class Member {
    private Long id;
    private String name;
    private Grade grade;
 
    public Member(Long id, String name, Grade grade) {
        this.id = id;
        this.name = name;
        this.grade = grade;
    }
 
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public Grade getGrade() {
        return grade;
    }
 
    public void setGrade(Grade grade) {
        this.grade = grade;
    }
}

<이후>

package com.naver.shopping.member;
 
import lombok.Getter;
import lombok.Setter;
 
@Getter
@Setter
public class Member {
    private Long id;
    private String name;
    private Grade grade;
 
    public Member(Long id, String name, Grade grade) {
        this.id = id;
        this.name = name;
        this.grade = grade;
    }
}

(Order 클래스에도 적용해 보세요! Order는 Setter적용은 하면 안 됩니다.)

엄청 간결해졌죠?  이 외에도 롬복이 지원하는 기능들이 많으니 관심 있으신 분들은 공식 사이트를 참조해 보시면 좋을 것 같아요!

Project Lombok 공식 사이트


추가) 빈이 여러 개일 때 다 가져오는 법

지난 시간에 빈을 조회해서 해당 타입의 빈이 여러 개면 한 개만 가져올 수 있도록 하는 방법을 알려드렸는데요, 근데 만약 다 필요하다면? 예를 들어 저희 프로젝트의 경우 어느 부분에서는 정률, 어느부분에서는 비율 할인 정책을 둘 다 써야 한다면 어떻게 해야 할지 알려드리겠습니다.

autoScanTest로 다시 돌아가봅시다.

    @Component
    static class OrderService3{
        private MemberRepository memberRepository;
        private Map<String, DiscountPolicy> discountPolicyMap;
 
        @Autowired
        public OrderService3(MemberRepository memberRepository, Map<String, DiscountPolicy> discountPolicyMap) {
            this.memberRepository = memberRepository;
            this.discountPolicyMap = discountPolicyMap;
        }
 
        public Order createOrder(Long memberId, String itemName, int itemPrice, String policyName) {
            Member member = memberRepository.findById(memberId);
            DiscountPolicy discountPolicy = discountPolicyMap.get(policyName);
            int discountPrice = discountPolicy.discount(member, itemPrice);
            return new Order(memberId, itemName, itemPrice, discountPrice);
        }
    }

위와 같이 OrderService3도 아래에 추가해 줍시다. createOrder()의 인자값에서 추가를 해야 해서 편의상 OrderService를 implements 하지 않았습니다.

OrderService3에서 바뀐 것은 discountPolicy를 그대로 받는 게 아니라 DiscountPolicy들을 Map형대로 받는다는 것입니다.

그리고 createOrder로 주문을 할 때, 해당 주문이 적용될 할인 정책을 입력받아서 그 정책에 맞게 주문에 따라 바꿀 수 있게 되었습니다.

바로 한번 써봅시다!

    @Test
    @DisplayName("여러 할인 정책 서비스중 선택")
    void getAllDiscountPolicy() {
        Member testMember = new Member(1L, "tester", Grade.VIP);
        ac.getBean(MemberService.class).join(testMember);
 
        Order fixServiceOrder = ac.getBean(OrderService3.class).createOrder(1L, "아이템1", 20000, "fixDiscountPolicy");
        Order rateServiceOrder = ac.getBean(OrderService3.class).createOrder(1L, "아이템1", 20000, "rateDiscountPolicy");
 
        System.out.println("fixServiceOrder = " + fixServiceOrder);
        System.out.println("rateServiceOrder = " + rateServiceOrder);
 
        Assertions.assertThat(fixServiceOrder.getDiscountPrice()).isEqualTo(1000);
        Assertions.assertThat(rateServiceOrder.getDiscountPrice()).isEqualTo(2000);
    }

createOrder의 마지막 부분에 여러 개 잡힌 DiscountPolicy타입의 빈 중 원하는 빈의 이름을 넣어주면 해당 정책으로 할인이 될 것입니다.

실행 결과

각각의 주문별로 할인금액이 잘 들어간 것을 확인하실 수 있습니다.


마치며

오늘은 이렇게 롬복의 편의성과 할인정책을 선택할 수 있는 방법에 대해서도 알아보았습니다.

이제 뭔가 좀 멋있는 기능들도 쓰는 거 같고 만드는 결과물이 느낌이 나지 않나요?

환상적인 프로젝트를 만드는 그날까지 달려봅시다!!!!!

오늘 작업한 내용은 아래 커밋에서 확인하실 수 있습니다.

Use Lombok and add choosing from many beans · KIMB0B/blog_spring@8010e55 (github.com)

👉다음 글 보러가기