Spring

Spring ๊ธฐ๋ณธ [ํ• ์ธ์ •์ฑ… ๋ณ€๊ฒฝ/๊ฐ์ฒด ์ง€ํ–ฅ ์›๋ฆฌ ์ ์šฉ/DI/์Šคํ”„๋ง์ปจํ…Œ์ด๋„ˆ]

DAHLIA CHOI 2021. 7. 8. 17:33

์ง€๊ธˆ๊นŒ์ง€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ ์„ค๋ช…

ํšŒ์›๊ฐ€์ž…์„ ํ•˜๊ณ , ์กฐํšŒํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.

๋ฌผ๊ฑด์„ ๊ตฌ์ž…ํ•  ๋•Œ ํ• ์ธ ์ •์ฑ…์„ ๋งŒ๋“ค๊ณ  ์‹ถ์–ด์„œ ๊ณ ์ •๋œ ํ• ์ธ๊ธˆ์•ก์„ ํ• ์ธํ•ด์ฃผ๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.

 


๊ทธ๋Ÿฐ๋ฐ ๊ธฐ์—…์—์„œ ๊ณ ์ •๋œ ํ• ์ธ๊ธˆ์•ก์ด ์•„๋‹ˆ๋ผ ํผ์„ผํŠธ๋กœ ํ• ์ธํ•ด์ฃผ๊ณ  ์‹ถ๋‹ค๊ณ  ํ•˜๋ฉด ์ฝ”๋“œ๋ฅผ ๋ฐ”๊ฟ”์•ผํ•œ๋‹ค.

package hello.core.discount;

import hello.core.member.Grade;
import hello.core.member.Member;

public class RateDiscountPolicy implements DiscountPolicy {

    private int discountPercent = 10;

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

JAVA๋ฅผ ๋ฐฐ์šฐ๋ฉด์„œ enum์„ ์“ธ ์ผ์ด ์—†์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋Š”๋ฐ ์ด๋ฒˆ ์‹ค์Šต์„ ํ•˜๋ฉด์„œ enum๋ฅผ ์ž์ฃผ ์‚ฌ์šฉ ํ•˜๊ฒŒ ๋  ๊ฒƒ ๊ฐ™๋‹ค๊ณ  ๋А๊ผˆ๋‹ค..์จ‹๋“ !

 

10ํผ์„ผํŠธ๋ฅผ ํ• ์ธํ•ด์ฃผ๋Š” ์ •์ฑ… ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ , ํด๋ผ์ด์–ธํŠธ์—์„œ ๋ณ€๊ฒฝํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

 

๊ทผ๋ฐ ๊ฐ์ฒด์ง€ํ–ฅ 5๊ฐ€์ง€ ์›์น™์ค‘์—์„œ OCP๋ฅผ ์œ„๋ฐ˜ํ•˜๊ณ  ์žˆ๋‹ค. 

์ด ์ „ ํฌ์ŠคํŒ…์„ ๋ณด๋ฉด OCP ์›์น™์€ ํ™•์žฅ์—๋Š” ์—ด๋ ค์žˆ์œผ๋‚˜ ๋ณ€๊ฒฝ์—๋Š” ๋‹ซํ˜€์žˆ์–ด์•ผ ํ•œ๋‹ค๊ณ  ํ–ˆ๋‹ค. 

๊ทผ๋ฐ ์œ„์™€ ๊ฐ™์€ ์ฝ”๋“œ์—์„œ๋Š” ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๊นŒ์ง€ ๋ณ€๊ฒฝํ•ด์•ผํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊ธด๋‹ค.

 

์ด์ฒ˜๋Ÿผ ๊ณ ์ •๊ธˆ์•ก์—์„œ ๋น„์œจ๊ธˆ์•ก์œผ๋กœ ๋ฐ”๋€”๋•Œ ์ธํ„ฐํŽ˜์ด์Šค๋งŒ๋“ค ์˜์กดํ•˜๊ณ  ์žˆ๋Š” ์ค„ ์•Œ์•˜๋Š”๋ฐ, ๊ตฌ์ฒดํด๋ž˜์Šค๋„ ์˜์กดํ•˜๊ณ  ์žˆ๊ณ , ์ •์ฑ…์„ ๋ฐ”๊ฟ€ ๋•Œ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๊นŒ์ง€ ๋ณ€๊ฒฝํ•ด์•ผํ•œ๋‹ค. ๐Ÿ‘‰ DIP, OCP์œ„๋ฐ˜

 

DIP์œ„๋ฐ˜ ์‚ฌ์ง„, ์ถ”์ƒ์™€ ๊ตฌ์ฒด ๋ชจ๋‘์— ์˜์ง€ํ•˜๊ณ  ์žˆ์Œ

 

ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ์˜์กดํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๊ด€์‹ฌ์‚ฌ๋ฅผ ๋ถ„๋ฆฌํ•ด์•ผํ•œ๋‹ค!

 

AppConfig ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ ๊ตฌํ˜„๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์—ฐ๊ฒฐํ•ด์คฌ๋‹ค.

package hello.core;

import hello.core.discount.FixDiscountPolicy;
import hello.core.discount.RateDiscountPolicy;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.member.MemoryMemberRepository;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;


public class AppConfig {

    public MemberService memberService() {
        return new MemberServiceImpl(new MemoryMemberRepository());
    }

    public OrderService orderService(){
        return new OrderServiceImpl(new MemoryMemberRepository(), new RateDiscountPolicy());
    }
}

AppConfig๋ฅผ ์ด์šฉํ•ด์„œ ๊ตฌํ˜„๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด๊ณ , ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค ์ฐธ์กฐ๋ฅผ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด์„œ ์ฃผ์ž…ํ•ด์ค€๋‹ค.

 

package hello.core.member;

public class MemberServiceImpl implements MemberService{

    private final MemberRepository memberRepository;
    //์ถ”์ƒํ™”์—๋งŒ ์˜์กดํ•จ (DIP ์ง€ํ‚ด)
    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Override
    public void join(Member member) {
        memberRepository.save(member);
    }

    @Override
    public Member findMember(Long memberId) {
        return memberRepository.findById(memberId);
    }
}

์ƒ์„ฑ์ž๋ฅผ ๋งŒ๋“ค์–ด์„œ ์—ฐ๊ฒฐํ•ด์ผœ์ฃผ๋ฉด DIP๋ฅผ ์ง€ํ‚ฌ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

์ฃผ๋ฌธ์„œ๋น„์Šค๋„ ๋˜‘๊ฐ™์ด ๋ฐ”๊ฟ”์ฃผ์—ˆ๋‹ค. 

๊ทธ๋Ÿฌ๋ฉด AppConfig๊ฐ€ ๋ชจ๋“  ์˜์กด๊ด€๊ณ„๋ฅผ ๋„๋งก์•„์„œ ํ•˜๊ณ , MemberServiceImpl๋Š” ์‹คํ–‰๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

 

๊ทธ๋Ÿผ ์ด config๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋ฉ”์ธ ํด๋ž˜์Šค๋„ ์ˆ˜์ •ํ•ด์ค˜์•ผํ•œ๋‹ค.

AppConfig appConfig = new AppConfig();
MemberService memberService = appConfig.memberService();
OrderService orderService  = appConfig.orderService();

์ด๋ ‡๊ฒŒ config ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ณ  membersService์™€ orderService๊ฐ์ฒด๋ฅผ ์—ฐ๊ฒฐ์‹œ์ผœ์ฃผ๋ฉด ๋œ๋‹ค!

 

package hello.core.member;

import hello.core.AppConfig;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class MemberServiceTest {

    MemberService memberService;

    @BeforeEach
    // ์‹คํ–‰ํ•˜๊ธฐ ์ „์— ๋ฌด์กฐ๊ฑด ๋™์ž‘ํ•ด์•ผ๋จ
    public void beforeEach(){
        AppConfig appConfig = new AppConfig();
        memberService = appConfig.memberService();
    }

    @Test
    void join(){
        //given
        Member member = new Member(1L, "memberA", Grade.VIP);
        //when
        memberService.join(member);
        Member findMember = memberService.findMember(1L);
        //then
        Assertions.assertThat(member).isEqualTo(findMember);

    }
}

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์—๋„ DIP๋ฅผ ์œ„ํ•ด์„œ ๊ฐ์ฒด ์„ ์–ธ๋งŒ ํ•ด์ฃผ๊ณ  ํ…Œ์ŠคํŠธ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— Config๋ž‘ ๊ฐ์ฒด๋ž‘ ์—ฐ๊ฒฐ์‹œ์ผœ์ฃผ๋ฉด ๋œ๋‹ค!

 

์‹คํ–‰ํ•˜๋ฉด ์ „์ด๋ž‘ ๋˜‘๊ฐ™์€ ์‹คํ–‰๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜จ๋‹คโœชโ€ฟโœช 

 

์œ„์˜ AppConfig์—์„œ ์ค‘๋ณต๋œ ๊ฐ’์„ ์ œ๊ฑฐํ•˜๊ณ  ์ข€ ๋” ๊น”๋”ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ค€๋‹ค.

์—ญํ• ๊ณผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌ์„ฑ์„ ํ•œ๋ˆˆ์— ๋ณผ ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  ์ด๊ฑธ ์Šคํ”„๋ง๊ธฐ๋ฐ˜์œผ๋กœ ๋ณ€๊ฒฝํ–ˆ๋‹ค!!

 

package hello.core;

import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.discount.RateDiscountPolicy;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.member.MemoryMemberRepository;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration //AppConfig์— ์„ค์ •์„ ๊ตฌ์„ฑํ•œ๋‹ค๋Š” ๋œป
public class AppConfig {

    @Bean //์Šคํ”„๋ง ๋นˆ์— ๋“ฑ๋ก
    public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
    }

    @Bean
    public MemoryMemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }

    @Bean
    public OrderService orderService(){
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    }

    @Bean
    public DiscountPolicy discountPolicy(){
        return new RateDiscountPolicy();
    }
    //์—ญํ• ์ด ๋“œ๋Ÿฌ๋‚˜๊ฒŒ ๋ณ€๊ฒฝ
}
public class MemberApp {

    public static void main(String[] args) {
        //AppConfig appConfig = new AppConfig();
        //MemberService memberService = appConfig.memberService();

        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
        Member member = new Member(1L, "memberA", Grade.VIP );
        memberService.join(member);

        Member findMember = memberService.findMember(1L);
        System.out.println("new member = " + member.getName());
        System.out.println("find Member = " + findMember.getName());
    }
}

1. ApplicationContext = ์Šคํ”„๋ง์ปจํ…Œ์ด๋„ˆ๋ผ๊ณ  ํ•œ๋‹ค. 

2. .getBean("ํด๋ž˜์Šค ์ด๋ฆ„", ํด๋ž˜์Šค)๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ํด๋ž˜์Šค์ด๋ฆ„์— ํ•ด๋‹นํ•˜๋Š” ์Šคํ”„๋ง ๊ฐ์ฒด๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.

 ๐Ÿ‘‰ ํ•„์š”ํ•œ ์Šคํ”„๋ง ๋นˆ์„ ์•„๋ฌด๋•Œ๋‚˜ ์ฐพ์•„์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

 

 


โœ [์˜ค๋Š˜ ๋ฐฐ์šด ๊ฒƒ ์ค‘ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ฒƒ]

โž– DIP์™€ OCP๋ฅผ ์ค€์ˆ˜ํ•ด์•ผ๋จ

 

โž– ์ง์ ‘ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ๋‚˜์ค‘์— ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์žˆ์„ ๋•Œ ํด๋ผ์ด์–ธํŠธ๊นŒ์ง€ ๋ณ€๊ฒฝํ•ด์•ผํ•˜๋Š” ๋ฒˆ๊ฑฐ๋กœ์›€์ด ์ƒ๊ธด๋‹ค. 

     ํด๋ผ์ด์–ธํŠธ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๊ทธ ๊ฐ์ฒด ๊ด€๋ จ๋œ ์ฝ”๋“œ๋Š” ๋ชจ๋‘ ๋ณ€๊ฒฝํ•ด์ค˜์•ผ๋จ.

     ๊ฐ€์žฅ ์ค‘์š”ํ•˜๊ฒŒ๋Š” ์›์น™์— ์œ„๋ฐ˜๋œ๋‹ค.

 

โž– ๋‹คํ˜•์„ฑ๋งŒ ๊ฐ€์ง€๊ณ ๋Š” ํ•ด๊ฒฐ์ด ์•ˆ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์—ญํ• ์„ ๋ถ„๋ฆฌ์‹œ์ผœ์ค˜์•ผํ•œ๋‹ค.

 

โž– AppConfig๋ฅผ ๋งŒ๋“ค์–ด์„œ ๊ตฌํ˜„ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‹คํ–‰๊นŒ์ง€ ์‹œ์ผœ์ค€๋‹ค.

     ํด๋ผ์ด์–ธํŠธ ๊ตฌํ˜„ ๊ฐ์ฒด๊ฐ€ ์Šค์Šค๋กœ ํ•„์š”ํ•œ ์„œ๋ฒ„ ๊ตฌํ˜„ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ–ˆ๋˜ ํ”„๋กœ๊ทธ๋žจ์€ ์ด์ œ ์ž์‹ ์˜ ์—ญํ• ์—๋งŒ ์ถฉ์‹คํ•˜๋ฉด ๋จ

 

โž–์ด์ฒ˜๋Ÿผ ์ง์ ‘ ์ œ์–ด ํ๋ฆ„์„ ์ œ์–ดํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์™ธ๋ถ€์—์„œ ๊ด€๋ฆฌํ•ด์ฃผ๋Š” ๊ฒƒ์„ ์ œ์–ด์˜ ์—ญ์ „(IoC)๋ผ๊ณ  ํ•œ๋‹ค.

 

โž–์—ฌ๊ธฐ์„œ Config ์ฒ˜๋Ÿผ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋ฉด์„œ ์˜์กด๊ด€๊ณ„๋ฅผ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ๊ฒƒ์„ IoC์ปจํ…Œ์ด๋„ˆ ๋˜๋Š” DI์ปจํ…Œ์ด๋„ˆ๋ผ๊ณ  ํ•จ

 

โž–์Šคํ”„๋ง๊ธฐ๋ฐ˜์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋ ค๋ฉด AppConfig์— ์„ค์ •์„ ๊ตฌ์„ฑํ•œ๋‹ค๋Š” ๋œป์ธ @Configuration์„ ๋ถ™์—ฌ์ฃผ๊ณ  @Bean์„ ๋“ฑ๋กํ•˜๋ฉด      ๊ทธ ๋ฉ”์„œ๋“œ๋Š” ๋ชจ๋‘ ์Šคํ”„๋ง๋นˆ์œผ๋กœ ๋“ฑ๋ก๋œ๋‹ค. ์Šคํ”„๋ง๋นˆ์œผ๋กœ ๋“ฑ๋ก๋˜๋ฉด ํ•„์š”ํ• ๋•Œ ์–ธ์ œ๋“  ๊บผ๋‚ด ์“ธ ์ˆ˜ ์žˆ๋‹ค.

 

โž–๊ทธ๋Ÿฌ๋ฉด ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์žˆ์„ ๋•Œ AppConfig๋งŒ ์ˆ˜์ •ํ•˜๋ฉด ๋‹ค๋ฅธ ๊ฒƒ์€ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์•„๋„ ์ ์šฉ์ด ๋œ๋‹ค.

 

 


์ถœ์ฒ˜ : ์ธํ”„๋Ÿฐ ๊น€์˜ํ•œ๋‹˜ ๊ฐ•์˜ - 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/dashboard