@AutoConfiguration(after = DataSourceAutoConfiguration.class)
@ConditionalOnClass({ DataSource.class, JdbcTemplate.class })
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(JdbcProperties.class)
@Import({ DatabaseInitializationDependencyConfigurer.class, JdbcTemplateConfiguration.class,
NamedParameterJdbcTemplateConfiguration.class })
public class JdbcTemplateAutoConfiguration {
}
@AutoConfiguration = 자동구성을 사용하려면 이 애노테이션을 등록해야한다.
- 자동 구성도 내부에 @Configuration 이 있어서 빈을 등록하는 자바 설정 파일로 사용할 수 있다.
after = DataSouceAutoConfiguration.lcass
- 자동 구성이 실행되는 순서를 지정할 수 있다. JdbcTemplate은 DataSouce가 필요하기 때문에 DataSource를 자동으로 등록해주는 DataSourceAutoConfiguration 다음에 실행하도록 설정되어 있다.
@ConditionOnClass({DataSouce.class, JdbcTemplate.class})
- 괄호안에 클래스가 있는 경우에만 설정이 동작하게 된다.
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(JdbcOperations.class)
class JdbcTemplateConfiguration {
JdbcOperation은 jdbctemplate의 인터페이스이고
@ConditionalOnMissingBean에서 해당 인터페이스르 구현한 빈이 없을시에만 JdbcTemplate 자동구성을 진행하게 된다.
개발자가 이미 등록했으면 안동작함
@Conditional
같은 소스 코드인데 특정 상황일 때만 특정 빈들을 등록해서 사용하도록 도와주는 기능
@Slf4j
public class MemoryCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// -Dmemory=on
String memory = context.getEnvironment().getProperty("memory");
log.info("memory={}", memory);
return "on".equals(memory);
}
}
@Configuration
@Conditional(MemoryCondition.class)
public class MemoryConfig {
-Dmemory=on jvm option을 주면 해당 Configuration에 정의된 빈들을 등록해라
@ConditionalOnProperty(name = "memroy", havingValue = "on")
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {
위와같이 이미 스프링에서 이미 구현해 놓은것이다.
얘도 똑같이 OnPropertyCondition 클래스에서 Condition 인터페이스를 구현하고 있다.
순수 라이브러리 만들기
plugins {
id 'java'
}
group = 'memory'
sourceCompatibility = '17'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web:3.0.2'
compileOnly 'org.projectlombok:lombok:1.18.24'
annotationProcessor 'org.projectlombok:lombok:1.18.24'
testImplementation 'org.springframework.boot:spring-boot-starter-test:3.0.2'
}
test {
useJUnitPlatform()
}
스프링 부트 플러그인을 사용하게 되면 앞에 설명한 실행 가능한 jar를 만들기 떄문에 plugin에 java만 기본으로 있다.
스프링 부트 플러그인이 없기에 버전명시도 되어있다.
plugins {
id 'org.springframework.boot' version '3.0.2'
id 'io.spring.dependency-management' version '1.1.0'
id 'java'
}
group = 'hello'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation files('libs/memory-v1.jar')
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
사용하고자 하는곳에 해당 라이브러리를 등록해줘야한다.
또한 사용자입장에서는 어떤 클래스들을 빈으로 등록을 해줘야하는지 알 수 가 없다.
MemoryConfig를 구성하는 방법을 알아내야함
자동 구성 라이브러리 만들기
@AutoConfiguration
@ConditionalOnProperty(name = "memory", havingValue = "on")
public class MemoryAutoConfig {
@Bean
public MemoryFinder memoryFinder() {
return new MemoryFinder();
}
@Bean
public MemoryController memoryController() {
return new MemoryController(memoryFinder());
}
}
위에서 했던 @AutoConfiguration , @ConditionalOnProperty를 추가해서 라이브러리르 만든다.
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
memory.MemoryAutoConfig
인 클래스 풀네임을 해당 폴더에 적어줘야한다.
이제 이것을 library jar으로 만들어서 실제로 쓰는 스프링부트앱에서 dependency 등록만하면 부팅시점에 필요한 빈들을 알아서 등록하게 된다.
자동 구성 이해 - 스프링 부트의 동작
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
@SpringBootApplication 의 자식 Annotation (meta annotation) 에 selector가 존재한다.
@Import 에 설정정보를 추가하는 방법은 2가지이다.
정적인 방법 = @Import(클래스) , 설정으로 사용할 대상을 동적으로 변경할 수 없다.
동적인 방법 = @Import ( 'ImportSelector' 인터페이스 구현체 ) 를 사용해 동적으로 선택할 수 있다.
@Test
void selectorConfig() {
AnnotationConfigApplicationContext appContext =
new AnnotationConfigApplicationContext(SelectorConfig.class);
HelloBean bean = appContext.getBean(HelloBean.class);
Assertions.assertThat(bean).isNotNull();
}
@Configuration
@Import(HelloImportSelector.class)
public static class SelectorConfig {
}
public class HelloImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"hello.selector.HelloConfig"};
}
}
@Import에 바로 class 이름 넣는것은 바로 인식하는것이지만 ImportSelector 구현체를 넣으면 selectImport 메소드를 실행 시켜서 나오는 String 기준으로 classpath에서 찾아보게 된다.
ImportCandidates#load 에서 spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 해당 파일에 적혀있는것을 다 읽어 오게 된다.
'WEB > Spring Boot' 카테고리의 다른 글
액츄에이터 (0) | 2023.05.16 |
---|---|
외부설정과 프로필 (0) | 2023.05.14 |
스프링 부트 스타터와 라이브러리 관리 (0) | 2023.05.11 |
스프링 부트와 내장 톰캣 (0) | 2023.05.10 |
웹 서버와 서블릿 컨테이너 (0) | 2023.05.08 |