본문 바로가기

Java/Spring

@Configuration 어노테이션 개념과 특징

@Configuration

더보기

Indicates that a class declares one or more @Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime.

하나 이상의 @Bean 메소드를 선언한 설정(Configuration) 클래스가 Spring 컨테이너에 의해서 초기화되면, Spring은 Bean을 정의하고 런타임에 접근 할 수 있습니다.

 @Configuration
 public class AppConfig 
 {
     @Bean
     public MyBean myBean() 
     {
         // instantiate, configure and return bean ...
     }
 }

@Configuration은 설정 클래스에서 사용되지만 필수는 아닙니다.

컨테이너를 초기화 할 때 설정 클래스를 명시적으로 전달하기 때문에 어떤 클래스 파일이 설정 클래스인지 알기 때문입니다.

ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);

다시 말해 설정 클래스의 구분자 역할로 @Configuration을 등록하는 것은 아닙니다.

@Bean과 @Configuration

@Configuration은 설정 클래스에 대한 구분자가 아니며 별도의 용도를 갖고 있습니다.

테스트를 위해서 @Configuration을 제거합니다.

// @Configuration
public class AppConfig
{
	@Bean
	public MyBean myBean()
	{
		return new MyBean();
	}
	
	@Bean
	public YourBean yourBean()
	{
		return new YourBean(myBean());
	}
}

Bean 클래스에서는 생성자 내부에서 인스턴스 정보를 출력합니다.

package com.example.test;

public class MyBean
{
	public MyBean()
	{
		System.out.println("MyBean instanced: " + this);
	}
}

컨테이너에서 설정 클래스를 초기화 하고 Bean 객체에 접근합니다.

ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
MyBean myBean = ctx.getBean(MyBean.class);
YourBean yourBean = ctx.getBean(YourBean.class);

애플리케이션을 실행하면 다음과 같이 출력됩니다.

MyBean instanced: com.example.test.MyBean@124c278f
MyBean instanced: com.example.test.MyBean@15b204a1
YourBean instanced: com.example.test.YourBean@77167fb7
코드 비고
Line 1 MyBean instanced MyBean에 엑세스하였으며 MyBean 객체가 생성됩니다.
Line 2:3 MyBean instanced YourBean에 엑세스하였으며 MyBean 객체가 생성됩니다.
YourBean instanced YourBean에 엑세스하였으며 YourBean 객체가 생성됩니다.
더보기

예시의 YourBean은 MyBean을 의존 주입(DI)하고 있습니다.

Bean 객체는 싱글톤(Singleton)으로 알고 있었으나 테스트 결과 MyBean 생성자가 여러 번 호출되며 객체 역시 여러 번 인스턴싱 된 것을 알 수 있습니다.

비교를 위해서 @Configuration을 추가합니다. 애플리케이션을 실행하고 출력 결과를 확인합니다.

MyBean instanced: com.example.test.MyBean@385c9627
YourBean instanced: com.example.test.YourBean@139982de

기대했던 대로 의존 주입 관계에서 Bean이 싱글톤으로 동작하고 있습니다.

더보기

결과적으로 @Configuration은 Bean 객체를 싱글톤으로 처리하기 위해 사용합니다.

CGLIB(Code Generator Library)

Spring에서는 설정 클래스도 하나의 Bean으로 등록되고 관리됩니다.

ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
AppConfig cfg = ctx.getBean(AppConfig.class);
System.out.println(cfg);

예시에서는 설정 클래스 AppConfig를 Bean 객체로 가져와서 출력합니다.

이때 출력되는 클래스 경로는 AppConfig$$SpringCGLIB으로 우리가 실제 작성한 클래스 경로와 다릅니다.

com.example.test.AppConfig$$SpringCGLIB$$0@2e377400
더보기

비교를 위해 @Configuration을 제거하면 우리가 실제 작성한 클래스 경로가 표시됩니다.

com.example.test.AppConfig@67a20f67

Spring은 @Configuration이 등록된 설정 클래스를 처리하는 과정에서 CGLIB(Code Generator Library)을 사용해 Proxy 클래스를 생성합니다.

CGLIB은 바이트 조작 라이브러리로 생성된 Proxy 클래스는 설정 클래스를 상속합니다.

그리고 Bean 객체를 사용하는 코드에서 싱글톤으로 처리합니다.

package com.example.test;

public class MyBean
{
	public MyBean()
	{
		if ("MyBean이 Spring 컨테이너에 등록되어 있다면") {
			return "Spring 컨테이너에서 등록된 MyBean 객체를 반환"
		} else {
			"MyBean을 Spring 컨테이너에 등록"
			"이어서 원본 코드 실행"
			System.out.println("MyBean instanced: " + this);
		}
	}
}

실제 구현된 내용과는 다르지만  AppConfig$$SpringCGLIB의 예상 코드는 예시와 같이 동작할 것입니다.

정리 및 복습

  • @Configuration은 생략 가능합니다.
  • @Configuration을 등록하면 Bean 객체를 싱글톤(Singleton)으로 처리합니다.
  • @Configuration을 등록하면 Spring은 CGLIB(Code Generator Library)을 사용해 Proxy 클래스를 생성합니다.
  • Proxy 클래스는 설정 클래스를 상속하며 Bean 객체를 싱글톤으로 처리하는 동작이 포함됩니다.