@Configuration, @Bean

namkun·2022년 3월 8일
0

Spring

목록 보기
4/18

해당 내용은 '스프링 입문을 위한 자바 객체 지향의 원리와 이해'와 인프런 김영한님의 '스프링 핵심 원리 - 기본편' 강의를 참고하였습니다.


자 전의 자바 어플리케이션 코드를 이제 우리는 Spring 으로 변경하려고 한다.

우선 ApplicationConfig 파일부터 바꾸자.

다음과 같이 변경하면 된다.

@Configuration
public class ApplicationConfig {
    @Bean
    public Car carFuelTank() {
        return new CarImpl(getFuelTank());
    }

    @Bean
    public FuelTank getFuelTank() {
        return new GasolineOil();
//        return new ElectricBattery();
    }
}

@Configuration 어노테이션과 @Bean 어노테이션을 더해준다.
@Configuration 어노테이션은 Spring 설정 클래스라는 것을 선언한다.
그렇기에 Spring Container는 @Configration이 붙은 클래스를 설정정보로 사용한다.
@Bean어노테이션은 해당 메서드에서 반환된 객체들을 Spring Container에 등록시켜준다.
기본적으로는 메서드 이름으로 등록된다.

자 그 다음에는 자바 어플리케이션을 실행하는 쪽을 보자.

기존에는 ApplicationConfig 파일을 통해서 직접 DI를 해주었지만, 이젠 스프링컨테이너를 통해서 해보도록하자.

public class CarApp {
    public static void main(String[] args) {
        // DI 도입
//        ApplicationConfig applicationConfig = new ApplicationConfig();
//        Car car = applicationConfig.carFuelTank();

        // java to spring
        // spring container 생성
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationConfig.class);
        Car car = applicationContext.getBean("carFuelTank", Car.class);

        System.out.println("energy = " + car.runEngine().getEnergy());
    }
}

위의 코드에서 보이는 ApplicationContext가 위에서 말한 Spring Container이다.

Spring Container를 생성할 때, configuration 클래스(ApplicationConfig.class)를 구성정보로 지정해주면 해당 클래스에서 Bean 객체를 다시 등록한다.

보통 Bean의 이름은 기본적으로 클래스명을 사용하되 맨 앞글자만 소문자를 사용한다. 따로 @Bean(name = '???')로 직접 지정할 수 있다.

추가로 Bean의 이름은 모두 달라야한다. 같은 Bean이 여러개가 존재한다면 기존 Bean을 덮어쓰거나 오류가 발생할 수 있다.

이렇게 Bean들이 생성되면, 스프링 컨테이너는 Configuration 클래스를 참조해서 Bean 간의 의존관계를 주입한다.(DI)

이제 우리의 코드에서 등록한 Bean들이 잘 등록되는지 확인해보자.

간단하게 테스트 코드를 작성해보자.

public class ApplicationContextInfoTest {

	// 왜 앞에 interface가 아닌 구현 클래스를 썼냐면..상위 interface에는 bean을 조회하는 메서드가 없기때문
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ApplicationConfig.class);

    @Test
    @DisplayName("Application 빈 출력")
    void findApplicationBean(){
        String[] beanDefinitionNames = ac.getBeanDefinitionNames();
        for(String beanDefinitionName : beanDefinitionNames){
            BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);

            // BeanDefinition.ROLE_APPLICATION = 직접 등록한 애플리케이션 빈
            // BeanDefinition.ROLE_INFRASTRUCTURE = 스프링 내부에서 사용하는 빈
           if(beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION){
                System.out.println("beanDefinitionName = " + beanDefinitionName);
            }
        }
    }
}

결과는 다음과 같다. (Creating 생략)

beanDefinitionName = applicationConfig
beanDefinitionName = carFuelTank
beanDefinitionName = getFuelTank

우리가 등록한 config 파일(AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ApplicationConfig.class);에서 등록) 이외에도 @Bean으로 등록한 carFuelTank, getFuelTank 두 가지가 잘 등록된 것을 확인할 수 있다.

또한 Bean은 상속 관계도 적용된다.
그래서 부모 클래스에서 Bean을 조회하면, 그 아래의 자식 클래스도 모두 조회된다.

profile
개발하는 중국학과 사람

0개의 댓글