스프링 자동설정과 @Profile

2022. 10. 26. 13:12JAVA

최근 @Profile 이 어떻게 작동하는지에 대한 설명을 요청받았다.

무지성 구글링으로 갖다 쓴 것이라 당연히 대답하지 못했다.

'이 어노테이션을 쓰면 알아서 빈 등록을 해주는구나' 정도로만 이해하고 사용했다. 

사용하는 모든 기술의 코어를 파악하는 것은 현실적으로 어렵겠지만... 대략적인 그림은 그릴 수 있어야하지 않겠는가....!

 

질문받은 김에 @SpringBootApplication 에 대해서 조금 공부해보기로 했다.

 

허를 찌르는 질문 덕분에 또 관련 정보를 찾아보며 성장하는 계기가 되었다. 시작!

 

 


 

우선 SpringBoot 어플리케이션의 메인함수에 붙어있는 어노테이션을 살펴봅시다

@SpringBootApplication
public class TempApplication {
	public static void main(String[] args) {
		SpringApplication.run(TempApplication.class, args);
	}
}

 

@SpringBootApplication 이라는 어노테이션이 달려있습니다.

들어가보면,

 

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
...
}

또 여러 어노테이션이 달려있습니다.

여기서 가장 핵심이라고 생각되는 것들은 

@EnableAutoConfiguration 과 @ComponentScan 입니다.

 

@ComponentScan

컴포넌트스캔은 많이 아실 것이라고 생각합니다.

해당 어노테이션이 붙은 클래스의 하위 모든 패키지를 스캔하며 사용자가 정의한 컴포넌트 빈들을 컨테이너에 등록합니다.

 

 

 

@EnableAutoConfiguration

해당 어노테이션은 말 그대로 Auto Configuration을 활성화하겠다는 설정입니다.

SpringBoot는 spring.factories 정보를 가지고 자동설정을 진행한다고 합니다.

https://github.com/spring-projects/spring-boot/blob/main/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories

여기 적혀있는 클래스들은 @Configuration 어노테이션 없이도 자동으로 빈으로 등록됩니다. 

그 말인즉슨, spring.factories 파일을 수정해서 본인의 설정 클래스를 적어두면 @Configuration 어노테이션을 적지 않아도 된다는 사실!!!!!!!!!!!!!!!! 예,, 사실 쓸 일은 없겠습니다..

요약하면, 스프링 팩토리에 나열된 configuration 클래스들이 자동으로 빈 등록됩니다!

물론 항상 모든 빈을 다 등록하는 것은 아닙니다.

AutoConfigurationImportSelector 라는 친구가 조건에 분기해서 빈을 등록할지 말지 판단한다고 합니다.

잘 모르겠습니다만, 핵심은 @Condition 류의 어노테이션입니다.

(OnBeanCondition, OnClassCondition, OnWebApplicationCondition, @ConditionalOnBean, @ConditionalOnMissingBean 등등)

이 친구들 덕분에 우리가 만든 빈들이 스프링 auto configuration 빈들과 충돌하지 않습니다. 미리 스프링개발자 형님들이 다 계획적으로 구현해놓으셨습니다....

팩토리의 각 AutoConfigruation들은 필요한 상황에만 자신이 실행될 수 있도록 @Conditional, @Condition과 같은 annotation들로 설정이 되어있습니다. 그 annotation 을 기반으로 필터링이 먼저 이뤄지고 필터링되지 않은 AutoConfigruation을 가지고 작업이 진행됩니다.

이 때, @Profile 과 @Lazy 같은 spring 기술 어노테이션도 auto configuration에서 활용된다고 합니다!

 

우리가 .properties에 적어놓은 설정정보들도 이 때 활용됩니다.

 

 

많이 돌아오긴 했지만, @Profile을 살펴봅시다

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {
	/**
	 * The set of profiles for which the annotated component should be registered.
	 */
	String[] value();
}

아니나 다를까!!!!!!!!

이 친구도 @Conditional 이라는 어노테이션을 갖고 있습니다.

특정 조건이 만족되면 빈으로 등록된다는 약속입니다.

그리고, String[] value()라는 메서드를 갖고있습니다. 선언하는 곳에서 매개변수로 넘겨준 프로필 목록들이

스프링 컨테이너를 통해 빈 등록여부를 판가름합니다.

 

그리고, ProfileCondition.class 라는 클래스 내부에는 matches 라는 메서드가 있습니다.

class ProfileCondition implements Condition {
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
		if (attrs != null) {
			for (Object value : attrs.get("value")) {
				if (context.getEnvironment().acceptsProfiles(Profiles.of((String[]) value))) {
					return true;
				}
			}
			return false;
		}
		return true;
	}
}

이 matches 메서드에서 메타데이터와 여러가지를 짬뽕해서 @Conditional의 조건을 판단하는 것 같습니다.

아직은 배움이 미천하여,,,, 솔직히 잘은 모르겠습니다.

 

여튼,,, 이정도 까지만 알아도 감 잡는데는 충분했습니다!

두고보자 오토컨피규레이션 이놈자식!!!!!!!!!! 용두사미의 왕 감자 이창민!!!!!!!!!

 

 

 

https://velog.io/@jwkim/spring-boot-springapplication-annotation

 

[Spring Boot] @SpringBootApplication 파헤치기

[Spring Boot] @SpringBootApplication 얜 뭐지

velog.io

http://dveamer.github.io/backend/SpringBootAutoConfiguration.html#@SpringBootApplication

 

Dveamer

현실에서 살고 있지만 이상에 대한 꿈을 버리지 못한 몽상가의 홈페이지 입니다. 개인적인 기록을 주 목적으로 하며 일상과 프로그래밍 관련 글을 포스팅합니다.

dveamer.github.io