자바 클래스 간의 강결합을 느슨하게 바꾸기 - Spring Framework의 도움 받기

h.Im·2024년 9월 2일

Springboot 기초

목록 보기
14/17
post-thumbnail

이전에 작성한 자바 클래스 간의 강결합을 느슨하게 바꾸기 포스팅에서는 자바 클래스 간의 강결합을 느슨하게 하는 방법을 살펴보았습니다(서비스의 분리, 의존성 주입 등을 사용해서). 이번 포스팅에서는 Spring Framework의 도움을 받으면 코드가 얼마나 더 간결해질 수 있는지 공부해 보겠습니다.

Config 작성

package org.example.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

// org.example을 root로 삼아서 이 이하에 있는 빈들을 모두 스캔하겠다
@ComponentScan("org.example")
@Configuration
public class Config {

}

위와 같이 Config 클래스를 작성하고 @Configuration, @ComponentScan 어노테이션을 붙였습니다. @ComponentScan의 인자로 패키지명을 넣었는데, 넣은 패키지 하위의 빈들을 모두 스캔하겠다는 의미입니다.

package org.example;

import org.example.config.Config;
import org.example.logic.BubbleSort;
import org.example.logic.Sort;
import org.example.service.SortService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        // Config을 불러오는 코드 추가
        ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        SortService sortService = new SortService(new BubbleSort<>());
        System.out.println("result " + sortService.doSort(Arrays.asList(args)));
    }
}

Main 클래스도 위와 같이 수정하였습니다.
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
작성한 Config를 불러와서 사용하도록 수정되었네요.

그리고, 이전 포스팅에서 작성했던 JavaSort, BubbleSort, SortService에도 어노테이션을 붙여 빈으로 등록하겠습니다. 모두 org.example 패키지 아래에 작성하였으니 자동으로 스캔될 것입니다.

package org.example;

import org.example.config.Config;
import org.example.logic.BubbleSort;
import org.example.logic.Sort;
import org.example.service.SortService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        SortService sortService = context.getBean(SortService.class);
        System.out.println("result " + sortService.doSort(Arrays.asList(args)));
    }
}

빈이 등록되었으니 Main클래스를 위처럼 수정하여, new 키워드 없이 빈에 등록된 SortService를 getBean으로 가져와서 정렬을 수행하도록 해보겠습니다. 이전에 작성했던 MainTest를 이용해서 Main 함수를 테스트 해보면

package org.example;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class MainTest {

    @Test
    void main() {
        // given
        String[] args = {"3", "1", "2"};
        // when & then
        Main.main(args);
    }
}

No qualifying bean of type 'org.example.logic.Sort<java.lang.String>' available: expected single matching bean but found 2: bubbleSort,javaSort

위와 같은 에러가 발생하네요. 서비스 내부에 어떤 정렬 구현체를 사용해야 하는지 Spring에게 확실히 알려줄 필요가 있습니다.

package org.example.service;

import org.example.logic.JavaSort;
import org.example.logic.Sort;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class SortService {

    private final Sort<String> sort;

    public SortService(@Qualifier("bubbleSort") Sort<String> sort) {
        this.sort = sort;
    }

    public List<String> doSort(List<String> list) {
        return sort.sort(list);
    }
}

@Qualifier("bubbleSort") 어노테이션을 붙여, SortService 생성자에 bubbleSort 빈을 주입하였습니다. 서비스 코드를 이렇게 수정하고 다시 테스트 해보면, 정상적으로 테스트가 통과됨을 확인할 수 있습니다.

0개의 댓글