공부기록/Spring

Spring - DI 2

jhs0129 2021. 12. 16. 22:44
320x100
반응형

spring공부함에 있어서 내용은 인프런 김영한님 강의를 듣고 정리한 것입니다 (필기 및 공부정리용)

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8#

 

스프링 핵심 원리 - 기본편 - 인프런 | 강의

스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., 스프링 핵심 원리를 이해하고, 성장하는 개발자가 되어보세요! 📢 수강 전

www.inflearn.com

 

자동 의존관계 설정

자동 의존관계 사용이유

관리해야 할 객체들이 한 두개 정도면 직접 의존관계를 설정을 해주어도 상관이 없겠지만 프로젝트가 커지고 관리해야할 것들이 많아진다면 직접 관리를 하는데 있어서는 어려움이 있을 것이다.

이를 돕기위해 spring은 Autowired라는 어노테이션을 이용해 의존관계 설정을 자동으로 도와준다

의존관계 설정하기 전

설정 파일에 자동 의존관계 설정을 명시

자바코드기반 설정 방법

@ComponentScan을 사용

@Configuration
@ComponentScan(
        excludeFilters = @ComponentScan.Filter(type=FilterType.ANNOTATION, value = Configuration.class)
)
public class AutoAppConfig {
}

참고: @Configuration를 들어가보면 해당 어노테이션에도 @Component가 있는 것을 확일 할 수 있다. 해서 @Configuration을 사용한 파일까지 spring bean으로 등록이 되기때문에 제외를 한 것이다.
*type 속성 값에 올수 있는 것 - ANNOTATION, ASSIGNABLE_TYPE, REGEX, ASPECTJ

  • 컴포넌트 스캔의 기본 대상
    1. @Component
    2. @Controller - 스프링 MVC컨트롤러로 인식
    3. @Service - 부가적인 처리 없음 단순 계층인식 도움
    4. @Repository - 데이터 접근 계층으로 인식
    5. @Configuration - 스프링 설정정보 인식, 싱글톤 유지

xml기반 설정 방법

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans.xsd
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context.xsd">

    <!--추가-->
    <context:annotation-config/>

    <bean id="memberService" class="com.jhs.Member.MemberServiceImpl">
        <!--의존성 주입을 할 필요가 없음-->
    </bean>

    <bean id="orderService" class="com.jhs.Order.OrderServiceImpl">
        <!--의존성 주입을 할 필요가 없음-->
    </bean>

    <bean id="memberRepository" class="com.jhs.Member.MemoryMemberRepository"/>
    <bean id="discountPolicy" class="com.jhs.Discount.FixDiscountPolicy"/>
</beans>

컴포넌트 스캔

@ComponentScan

  • 프로젝트내에서 @Component가 붙은 모든 프로젝트를 스캔을 해서 spring bean으로 등록을 해준다
  • spring bean의 기본 이름은 클래스명의 앞글자를 소문자로 바꿔서 사용한다
  • `@Component("name") bean이름을 직접 지정하여 사용할 수 있다
  • 스캔 시작 위치를 지정할수 있다
    1. java 설정방법 @ComponentScan(basePackages="시작위치")
    2. xml 설정방법 <context:component-scan base-package="시작위치">

@Autowired

@Component //해당 어노테이션을 추가를 해준다
public class OrderServiceImpl implements OrderService {
    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;

    @Autowired //해당 어노테이션을 추가를 해준다
    public OrderServiceImpl(MemberRepository memberRepository, 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);
        return new Order(memberId, itemName, itemPrice, discountPrice);
    }
}
  • 컴포넌드 스캔을 통해서 등록된 spring bean을 조회하여 의존성을 주입을 해준다
  • 생성자가 하나만 있다면 @Autowired를 생략을 해도 된다

자동주입을 설정을 했는데 해당 bean이 없다면 에러가 생긴다

autowired 빈 중복 에러

이때 단순히 null값으로 유지를 하기를 원한다면 @Autowired(required=false)로 설정하여 존재하지 않아도 에러가 발생하지 않는다
주로 생성자로 의존성을 주입하는 것이 아닌 setter를 사용하여 주입을 하는경우 사용이 될듯 하다 개발자가 모르고 set을 하지 않았을 경우 혹은 하지 않아도 되는 경우와 같을때 사용이 될 것 같다

참고 의존성을 주입하는 방법에는 이외에도 필드를 통한 주입, 일반 메서드를 통한 주입 방법이 있지만 필드를 통한 주입은 외부에서 변경이 불가능 하고 di가 없으면 사용이 불가능하다
찾아보니 주로 생성자와 setter를 통한 주입 방식이 많이 사용되는 듯 하다

또한 생성자를 통한 주입을 할 시에는 final키워드를 통해서 필히 주입을 받게끔 만들고 주입이 되지 않는다면 컴파일 오류가 나서 찾기 쉽다

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

중복 빈 등록

@Component
public class FixDiscountPolicy implements DiscountPolicy {

    private final int discountFixAmount = 1000;
    @Override
    public int discount(Member member, int price) {
        if(member.getGrade() == Grade.VIP)
            return discountFixAmount;
        else
            return 0;
    }
}

@Component
public class RateDiscountPolicy implements DiscountPolicy {

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

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

orderservice는 discountPolicy라는 객체를 의존을 받아야 하는데 동일한 타입의 bean이 두개가 등록이 된다면 에러가 발생하게 된다

이를 방지하기 위해서 @Qualifier, @Primary를 사용을 하면 된다 spring bean특정시킨다고 생각을 하면 될 것 같다

설정방법

  1. xml 기반설정
<context:annotation-config/>

    <bean id="memberService" class="com.jhs.Member.MemberServiceImpl">
    </bean>

    <bean id="orderService" class="com.jhs.Order.OrderServiceImpl">

    </bean>

    <bean id="memberRepository" class="com.jhs.Member.MemoryMemberRepository"/>
    <bean id="fixdiscountPolicy" class="com.jhs.Discount.FixDiscountPolicy"/>
    <bean id="ratediscountPolicy" class="com.jhs.Discount.RateDiscountPolicy">
        <qualifier value="primary"/> <!--추가-->
    </bean>
  1. java 기반설정
@Component
@Qualifier("primary")//추가
public class RateDiscountPolicy implements DiscountPolicy {

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

}
  1. 사용방법
@Autowired
    public OrderServiceImpl(MemberRepository memberRepository,
    @Qualifier("primary")/*추가*/ DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }

위 예시에서 Qualifier의 이름을 primary로 지정을 하였는데 Qualifier을 사용하는 것이 아닌 @Primary를 사용하여 우선순위를 줄 수도 있다

@Component
@primary //추가
public class RateDiscountPolicy implements DiscountPolicy {

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

}

@Qualifier@Primary를 둘다 사용 할 경우에는 @Qualifier가 우선순위가 더 높게 설정 된다

 

spring공부함에 있어서 내용은 인프런 김영한님 강의를 듣고 정리한 것입니다 (필기 및 공부정리용)

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8#

 

스프링 핵심 원리 - 기본편 - 인프런 | 강의

스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., 스프링 핵심 원리를 이해하고, 성장하는 개발자가 되어보세요! 📢 수강 전

www.inflearn.com

 

320x100
반응형