Spring

[Spring] 자바 설정 빈 객체 생성 방법

재담 2022. 2. 10. 00:19

우선 다음 코드를 보자.

@Configuration
public class Config {
    @Bean
    public UserRepository userRepository() { ... }

    @Bean
    public PasswordChangeService pwChangeSvc() {
        return new PasswordChangeService(userRepository());
    }

    @Bean
    public AuthenticationService authenticationService() {
        AuthenticationService authSvc = new AuthenticationService();
        authSvc.setUserRepository(userRepository());
        return authSvc;
    }
    
    // 이하 생략
    ...
}

자바 설정을 이용한 DI를 설명할 때 메서드를 여러 번 호출해도 실제로는 동일한 객체만 리턴된다고 했는데, 그 이유는 스프링이 설정 클래스를 상속받아 새로운 클래스를 만들어내기 때문이다. 예를 들어 위의 Config 클래스를 스프링 설정으로 사용할 경우, 스프링은 다음과 비슷한 방식으로 동작하는 하위 클래스를 생성한 뒤에 그 클래스를 이용해서 설정 정보를 사용한다.

public class SpringGenConfig extends Config {
    private UserRepository userRepository;
    
    @Override
    public UserRepository userRepository() {
        if (userRepository == null) {
            userRepository = super.userRepository();
        }
        
        return userRepository;
    }
    
    // 다른 @Bean 메서드들도 비슷하게 재정의
    ...
}

위 코드에서 userRepository() 메서드는 상위 클래스에 정의된 userRepository() 메서드를 재정의하고 있는데, userRepository 필드가 null 이면 상위 클래스의 userRepository() 메서드를 호출해서 userRepository 필드에 할당하고 리턴한다. 따라서 userRepository() 메서드가 여러 번 호출되더라도 userRepository 필드에 할당된 동일한 객체를 리턴하게 된다.

 

실제 스프링은 하위 클래스를 생성할 때 CGLIB라는 도구를 이용해서 런타임에 하위 클래스를 생성한다. 하위 클래스를 만들고 메서드를 재정의하기 때문에, @Configuration 클래스와 @Bean 메서드는 final이면 안 된다. 또한 @Bean 메서드는 하위 클래스에서 재정의 할 수 있도록 하기 때문에 private이면 안 된다.