AppConfig

이 게시글은 개인 공부용으로 AppConfig의 발전 단계를 코드별로 정리한 것입니다.

김영한님의 “스프링 핵심 원리 - 기본편” 의 내용을 참조한 것입니다.

변수 및 메소드명을 변경하였습니다.

스프링 핵심 원리 - 기본편

AppConfig 이전

KokApp

public static void main(String[] args) {

    KokService kokService = new KokServiceImpl();
}

JumunApp

public static void main(String[] args) {

    KokService kokService = new KokServiceImpl();
    JumunService jumunService = new JumunServiceImpl();

}

AppConfig 이후

public class AppConfig {

    public KokService kokService() {
        return new KokServiceImpl(new MemoryKokRepository());
    }

    public JumunService jumunService() {
        return new JumunServiceImpl(
            new MemoryKokRepository(),
            new FixWaribikiPolicy()
        );
    }

}

KokServiceImpl - 생성자 주입

public class KokServiceImpl implements KokService {

    private final KokRepository kokRepository;

    public KokServiceImpl(KokRepository kokRepository) {
        this.kokRepository = kokRepository;
    }
}

JumunServiceImpl - 생성자 주입

public class JumunServiceImpl implements JumunService {
    
    private final KokRepository kokRepository;
    private final WaribikiPolicy waribikiPolicy;

    public JumunServiceImpl(KokRepository kokRepository, WaribikiPolicy waribikiPolicy) {
        this.kokRepository = kokRepository;
        this.waribikiPolicy = waribikiPolicy;
    }

}

AppConfig 실행

사용 클래스 - KokApp

public class KokApp {

    public static void main(String[] args) {

        AppConfig appConfig = new AppConfig();
        KokService kokService = appConfig.kokService();

    }

}

사용 클래스 - JumunApp

public class JumunApp {

    public static void main(String[] args) {

        AppConfig appConfig = new AppConfig();
        KokService kokService = appConfig.kokService();
        JumunService jumunService = appConfig.jumunService();

    }

}

AppConfig 리팩터링

public class AppConfig {

    public KokService kokService() {
        return new KokServiceImpl(new MemoryKokRepository());
    }

    public JumunService jumunService() {
        return new JumunServiceImpl(
            new MemoryKokRepository(),
            new FixWaribikiPolicy()
        );
    }

}

public class AppConfig {

    public KokService kokService() {
        return new KokServiceImpl(kokRepository());
    }

    public JumunService jumunService() {
        return new JumunServiceImpl(kokRepository(), waribikiPolicy());
    }

    public KokRepository kokRepository() {
        return new MemoryKokRepository();
    }

    public WaribikiPolicy waribikiPolicy() {
        return new FixWaribikiPolicy();
    }

}

AppConfig 스프링 기반으로 변경

@Configuration 
public class AppConfig {

    @Bean 
    public KokService kokService() {
        return new KokServiceImpl(kokRepository());
    }

    @Bean 
    public JumunService jumunService() {
        return new JumunServiceImpl(kokRepository(), waribikiPolicy());
    }

    @Bean 
    public KokRepository kokRepository() {
        return new MemoryKokRepository();
    }

    @Bean 
    public WaribikiPolicy waribikiPolicy() {
        return new RateWaribikiPolicy();
    }

}

KokApp에 스프링 컨테이너 적용

public class KokApp {
    public static void main(String[] args) {
        // AppConfig appConfig = new AppConfig();
        // KokService kokService = appConfig.kokService();
        ApplicationContext applicationContext = 
            new AnnotationConfigApplicationContext(AppConfig.class);

        KokService kokService = 
            applicationContext.getBean("kokService", KokService.class);
    }
}

JumunApp에 스프링 컨테이너 적용

public class JumunApp {
    
    public static void main(String[] args) {
        // AppConfig appConfig = new AppConfig();
        // KokService kokService = appConfig.kokService();
        // JumunService jumunService = appConfig.jumunService();
        ApplicationContext applicationContext = 
            new AnnotationConfigApplicationContext(AppConfig.class);

        KokService kokService = 
            applicationContext.getBean("kokService", KokService.class);

        JumunService jumunService = 
            applicationContext.getBean("jumunService", JumunService.class);
    }
}

컴포넌트 스캔과 의존관계 자동 주입

AutoAppConfig.java

@Configuration 
@ComponentScan
public class AutoAppConfig {

}

MemoryKokRepository @Component 추가

@Component
public class MemoryKokRepository implements KokRepository {}

RateWaribikiPolicy @Component 추가

@Component
public class RateWaribikiPolicy implements WaribikiPolicy {}

KokServiceImpl @Component, @Autowired 추가

@Component 
public class KokServiceImpl implements KokService {

    private final KokRepository kokRepository;

    @Autowired 
    public KokServiceImpl(KokRepository kokRepository) {
        this.kokRepository = kokRepository;
    }

}

JumunServiceImpl @Component, @Autowired 추가

@Component 
public class JumunServiceImpl implements JumunService {

    private final KokRepository kokRepository;
    private final WaribikiPolicy waribikiPolicy;

    @Autowired 
    public JumunServiceImpl(KokRepository kokRepository, WaribikiPolicy waribikiPolicy) {
        this.kokRepository = kokRepository;
        this.waribikiPolicy = waribikiPolicy;
    }
}

AutoAppConfigTest.java

public class AutoAppConfigTest {
    @Test void 
    basicScan() {
        ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class);
        KokService kokService = ac.getBean(KokService.class);
        assertThat(kokService).isInstanceOf(KokService.class);
    }
}

롬복과 최신 트랜드

기본 코드

@Component 
public class JumunServiceImpl implements JumunService {

    private final KokRepository kokRepository;
    private final WaribikiPolicy waribikiPolicy;

    @Autowired // 생성자가 딱 1개만 있으면 @Autowired 를 생략할 수 있다.
    public JumunServiceImpl(KokRepository kokRepository, WaribikiPolicy waribikiPolicy) {
        this.kokRepository = kokRepository;
        this.waribikiPolicy = waribikiPolicy;
    }

}

결과 코드

@Component 
@RequiredArgsConstructor 
public class JumunServiceImpl implements JumunService {

    private final KokRepository kokRepository;
    private final WaribikiPolicy waribikiPolicy;

}

롬복 라이브러리가 제공하는 @RequiredArgsConstructor 기능을 사용하면 final이 붙은 필드를 모아서 생성자를 자동으로 만들어준다.