이를 어기면 매우 큰 장애가 발생할 수 있기 때문에 주의해야 한다.
스프링은 @Configuration이 붙은 클래스 파일을 그대로 스프링 빈으로 등록하지 않고 CGLIB라는 바이트코드 조작 라이브러리를 사용해서 @Configuration이 붙은 클래스를 상속받은 임의의 다른 클래스를 생성하고, 그 클래스를 스프링 빈으로 등록한다.
임의로 생성된 그 클래스는 스프링 빈을 싱글톤으로 보장해준다. 스프링 빈이 이미 스프링 컨테이너에 등록되어 있으면 반환해주고, 없다면 스프링 빈을 등록한다.
추가적으로 AppConfig라는 설정 파일이 있다고 할 때, 스프링 컨테이너에서 AppConfig를 조회하면 해당 빈이 조회가 된다. 원래라면 AppConfig가 아니라 CGLIB 라이브러리가 생성한 클래스가 스프링 빈으로 등록되겠지만 이는 AppConfig를 상속 받았으므로 스프링은 부모 타입의 빈 호출시 자식 타입도 모두 호출되기 때문에 이러한 경우로 인해 AppConfig가 정상적으로 호출되는 것이다.
만약 AppConfig라는 설정 파일에 @Configuration 어노테이션을 붙이지 않는다면 CGLIB가 아닌, AppConfig 클래스 자체가 스프링 빈으로 등록될 것이다. 그러나 AppConfig 내부의 @Bean으로 등록된 빈들은 싱글톤으로 등록되지 않고 매번 호출 시마다 새로운 인스턴스를 생성할 것이다.
흔히 착각하는게 @Configuration 어노테이션을 붙여야만 해당 클래스가 스프링 빈으로 등록된다고 생각한다. 그러나 이는 사실이 아니다.

@Configuration 어노테이션의 내부를 살펴보면 @Component 어노테이션이 붙어있는걸 볼 수 있다. 이 어노테이션에 의해 스프링 컨테이너는 @Configuration이 붙은 클래스를 스프링 빈으로 등록하게 되며, 이것이 스프링 설정 클래스일 경우 내부 @Bean으로 설정한 객체들까지 모두 빈으로 등록하는 연쇄 반응효과가 나타나는 것이다.
바로 여기서 착각을 한다. @Configuration을 붙여야만 스프링 빈으로 등록된다고 말이다. 참고로 스프링 부트의 시작점인 @SpringBootApplication 내부엔 @Component 어노테이션들을 추적해내는 @ComponentScan 어노테이션을 포함한다.
다시 돌아와 아래와 같이 스프링 컨테이너를 만들면 어떻게 될까?
new AnnotationConfigApplicationContext(AppConfig.class);
이러한 코드가 있을 때 AppConfig 또한 스프링 컨테이너가 빈으로 등록한다. 물론 AppConfig 클래스에 @Configuration이 전혀 없어도 빈으로 등록된다. 스프링 컨테이너를 만들 때 파라미터로 클래스를 넘겨주면 해당 클래스를 스프링 빈으로 등록해주는 특별한 기능이 있다.
추가적으로 스프링 부트를 사용할땐 이렇게 개발자가 직접 new 로 스프링 컨테이너를 생성하여 사용할 경우엔 스프링 부트를 사용하는 것이 아니라 순수 스프링을 사용하는 것이 된다.
개발자는 @SpringBootApplication 어노테이션이 붙은 main 메서드를 통해서 애플리케이션을 실행시킬 때 비로소 스프링 부트를 사용하게 되는 것이다.