본문 바로가기
스프링/핵심 원리

[Spring] 애노테이션 직접 만들기

by drCode 2022. 3. 2.
728x90
반응형

@Qualifier("mainDiscountPolicy") 이렇게 문자르 ㄹ적으면 컴파일 시 타입 체크가 안된다. 다음과 같은 애노테이션을 만들어서 문제를 해결할 수 있다.

 

core.annotation.MainDiscountPolicy.java

Qualifier에서 

 

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented

를 복사해서

 

package hello.core.annotation;

import java.lang.annotation.*;

public @interface MainDiscountPolicy {
}

public 위에 복사한다.

 

package hello.core.annotation;

import org.springframework.beans.factory.annotation.Qualifier;

import java.lang.annotation.*;

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Qualifier("mainDiscountPolicy")
public @interface MainDiscountPolicy {
}

 

그리고 @Qualifier("mainDiscountPolicy")를 같이 적어준다.

 

위의 어노테이션들을 붙여주면 스프링 컨테이너 안에서 추가한 어노테이션들의 기능이 동작한다.

 

이제 만든 위의 어노테이션을 사용하러 가보자.

 

RateDiscountPolicy.java

package hello.core.discount;

import hello.core.annotation.MainDiscountPolicy;
import hello.core.member.Grade;
import hello.core.member.Member;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

@Component
//@Primary
@MainDiscountPolicy
public class RateDiscountPolicy implements DiscountPolicy{

    private int discountPercent = 10;

    // 쉽고 빠른 테스트 코드 만들기
    // 테스트 하기를 원하는 메서드에 마우스 포인트를 찍어놓고 Ctrl + Shift + T

    @Override
    public int discount(Member member, int price) {
        if(member.getGrade() == Grade.VIP) {
            return price * discountPercent / 100;
        } else {
            return 0;
        }
    }
}

 

RateDiscountPolicy.java 에서 @MainDiscountPolicy 어노테이션을 추가해주고,

 

OrderServiceImpl.java

package hello.core.order;

import hello.core.annotation.MainDiscountPolicy;
import hello.core.discount.DiscountPolicy;
import hello.core.member.Member;
import hello.core.member.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
//@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {

    // final을 붙이면 생성자에서만 쓸 수 있는 것이 장점
    // final이 붙으면 무조건 필수로 초기화 되어야하는 값이 된다.
    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;

    @Autowired
    public OrderServiceImpl(MemberRepository memberRepository, @MainDiscountPolicy DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }

    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        Member member = memberRepository.findById(memberId);
        int discountPrice = discountPolicy.discount(member, itemPrice); // SRD를 잘 지킨 형식

        return new Order(memberId, itemName, itemPrice, discountPrice);
    }

    // 테스트 용도
    public MemberRepository getMemberRepository() {
        return memberRepository;
    }
}

 

생성자의 파라미터에서 DiscountPolicy 부분 앞에 @MainDiscountPolicy를 붙여주고

 

test에서 Run > All Tests로 전체 테스트 실행 하면

 

전체 테스트가 통과하는 모습을 볼 수 있다.

 

애노테이션에는 상속이라는 개념이 없다. 이렇게 여러 애노테이션을 모아서 사용하는 기능은 스프링이 지원해주는 기능이다. 

@Qualifier 뿐만 아니라 다른 애노테이션들도 함께 조합해서 사용할 수 있다.

단적으로 @Autowired도 재정의 할 수 있다. 물론 스프링이 제공하는 기능을 뚜렷한 목적 없이 무분별하게 재정의하는 것은 유지보수에 더 혼란만 가중할 수 있다.

728x90
반응형

댓글