부트 개념과 활용-03.자동 설정 이해/만들기(Starter와 AutoConfigure/@Configuration)
자동 설정 이해
@EnableAutoConfiguration
@SpringBootApplication 안에 @EnableAutoConfiguration이 들어있다. (@ComponentScan도 마찬가지.. 이미 앞에서 정리했으니 생략)
- 빈은 사실 두 단계로 나눠서 읽힌다.
- 1단계: @ComponentScan
- 2단계: @EnableAutoConfiguration
- @ComponentScan
- @Component
- @Configuration @Repository @Service @Controller @RestController (컴포넌트 어노테이션 기반)
- @EnableAutoConfiguration = org.springframework.boot.autoconfigure.EnableAutoConfiguration
- spring.factories (설정파일 등..)
- @Configuration (클래스로 만든 설정빈 등..)
- @ConditionalOnXxxYyyZzz
//@SpringBootConfiguration
//@ComponentScan // (1) 컴포넌트 스캔으로 등록한 다음
//@EnableAutoConfiguration // (2) 추가적인 빈들을 읽어서 빈들을 등록
@Configuration // 컴포넌트 어노테이션 기반
@ComponentScan // @EnableAutoConfiguration 없어도 실행 잘됨
public class Application {
public static void main(String[] args){
// 웹서버 안띄우고 실행
SpringApplication application = new SpringApplication(Application.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.run(args);
//SpringApplication.run(Application.class, args);
}
}
그 빈들은 외부 라이브러리(External Libraries)중 spring-boot-autoconfigure에 정의되어 있다.
EnableAutoConfiguration
- spring.factories 해당 설정파일 안에는 이런 식으로
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnClassCondition
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguratio
...
key=value, value2… 타입으로
자동 설정되어서 생성될 빈들이 미리 정의가 되어 있다. (# Auto Configure)
이걸 @EnableAutoConfiguration 가 여기에 미리 정의된 빈들을 가져와서 등록해준다.
자동 설정 만들기 1부 : Starter와 AutoConfigure
- Xxx-Spring-Boot-Autoconfigure 모듈: 자동 설정
- Xxx-Spring-Boot-Starter 모듈: 필요한 의존성 정의
- 그냥 하나로 만들고 싶을 때는?
- Xxx-Spring-Boot-Starter 하나에 다 넣어버려도 된다.
구현 방법
- 의존성 추가
- @Configuration 파일 작성
- src/main/resource/META-INF에 spring.factories 파일 만들기
- spring.factories 안에 자동 설정 파일 추가
- mvn install
신규 프로젝트 pom.xml
- 의존성 추가
~~~xml
~~~java
public class Holeman {
String name;
int howLong;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getHowLong() {
return howLong;
}
public void setHowLong(int howLong) {
this.howLong = howLong;
}
@Override
public String toString() {
return "Holeman{" +
"name='" + name + '\'' +
", howLong=" + howLong +
'}';
}
}
- @Configuration 파일 작성
// 홀로맨 빈을 리턴하는 설정파일 @Configuration public class HolemanConfiguration { @Bean public Holeman holeman(){ Holeman holeman = new Holeman(); holeman.setHowLong(5); holeman.setName("jaeuk"); return holeman; } }
- src/main/resource/META-INF에 spring.factories 파일 만들기
resuouces 에 META-INF 디렉토리 생성
spring.facotries 파일 생성 (이건 부트에 특화된게 아니라 스프링에서 있는 것, 스프링의 라이프사이클에 활용되거나 등)
- spring.factories 안에 자동 설정 파일 추가
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
me.jaeuk.HolemanConfiguration
<!-- EnableAutoConfiguration 켜져있으면, 키에 해당하는 값들을 쭉 읽게 될 것이고, 해당 빈 설정을 보고 쓴다.(me.jaeuk.HolemanConfiguration) -->
- mvn install
maven install 로 jar 파일을 생성하고
본래 프로젝트로 돌아가서
pom.xml 에 의존성 추가
<dependency>
<groupId>me.jaeuk</groupId>
<artifactId>jaeuk-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
[캡처]
@Component
public class HolomanRunner implements ApplicationRunner {
@Autowired
Holeman holeman;
@Override
public void run(ApplicationArguments args) throws Exception{
System.out.println(holeman);
}
}
실행하면
Holeman{name='jaeuk', howLong=5}
출력되는 것을 확인할 수 있다.
그렇다면
@SpringBootApplication
public class Application {
public static void main(String[] args){
// 웹서버 안띄우고 실행
SpringApplication application = new SpringApplication(Application.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.run(args);
//SpringApplication.run(Application.class, args);
}
// 직접 빈으로 선언(컴포넌트 스캔과 순서 동일) / (1) 먼저 컴포넌트 스캔으로 빈 생성 -> (2) 추후 기타 빈 생성 (즉, 이건 덮어쓰인다)
@Bean
public Holeman holeman() {
Holeman holeman = new Holeman();
holeman.setName("suhun");
holeman.setHowLong(30);
return holeman;
}
}
이 경우에는 어떻게 출력이 될까?
Holeman{name='jaeuk', howLong=5}
로 동일하다. 왜냐햐면 앞서 말했듯,
- 컴포넌트 스캔으로 빈을 등록 한 다음
- 오토컨피규레이션으로 빈을 등록한다.
그런데 우리는 직접 @Bean 으로 생성이 되는게 더 우선시 되어야 한다.(1.이 더 우선되어야한다.)
그럼 어떤 해결 방법이 있을까?
자동 설정 만들기 2부 : @ConfigurationProperties
- 덮어쓰기 방지하기
- @ConditionalOnMissingBean
- 빈 재정의 수고 덜기
- @ConfigurationProperties(“holoman”)
- @EnableConfigurationProperties(HolomanProperties)
- 프로퍼티 키값 자동 완성
@ConditionalOnMissingBean를 활용하면 된다.
아까 설정파일을 jar로 배포한 그 프로젝트에서 이렇게 수정해주면 된다.
// 홀로맨 빈을 리턴하는 설정파일
@Configuration
public class HolemanConfiguration {
@Bean
@ConditionalOnMissingBean // 빈이 없는 것만 등록. (내가 직접 빈 선해 놓은거 있으면 등록안함.=덮어쓰지 않음)
public Holeman holeman(){
Holeman holeman = new Holeman();
holeman.setHowLong(5);
holeman.setName("jaeuk");
return holeman;
}
}
그럼 본 프로젝트로 돌아가서 돌려보면
@SpringBootApplication
public class Application {
public static void main(String[] args){
// 웹서버 안띄우고 실행
SpringApplication application = new SpringApplication(Application.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.run(args);
}
// (1) 먼저 컴포넌트 스캔으로 빈 생성 -> (2) 추후 기타 빈 생성 (즉, 이건 덮어인다)
// 설정(컨피규레이션)파일에 @ConditionalOnMissingBean 붙어놓음.
@Bean
public Holeman holeman() {
Holeman holeman = new Holeman();
holeman.setName("suhun");
holeman.setHowLong(30);
return holeman;
}
}
Holeman{name='suhun', howLong=30}
직접 생성하는 빈으로 적용 된 것을 볼 수 있다.
그렇다면 난 본 프로젝트에서 그냥 저렇게 빈을 새로 생성하는 것 보다,
그냥 프로퍼티에 값만 바꾸어서 사용하고 싶다면?
다른 방법이 있다.
본 프로젝트에서 application.properties를 만들고 사용하는 방법이다.
ex.
holeman.name = 꾸준히 공부를 해야죠.
holeman.how-long = 27
jar 배포한 프로젝트
spring.factorites
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
me.jaeuk.HolomanConfiguration
HolomanConfiguration를 오토 컨피그레이션(AutoConfiguration)해 주고,
// 홀로맨 빈을 리턴하는 설정파일
@Configuration
@EnableConfigurationProperties(HolomanProperties.class)
public class HolomanConfiguration {
@Bean
@ConditionalOnMissingBean // 빈이 없는 것만 등록. (내가 직접 빈 선해 놓은거 있으면 등록안함.=덮어쓰지 않음)
public Holoman holoman(HolomanProperties properties){
Holoman holoman = new Holoman();
holoman.setHowLong(properties.getHowLong());
holoman.setName(properties.getName());
return holoman;
}
}
@EnableConfigurationProperties 로 HolomanProperties.class 프로퍼티 설정파일을 컨피그레이션 해 준다.
@ConfigurationProperties("holoman")
public class HolomanProperties {
private String name;
private int howLong;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getHowLong() {
return howLong;
}
public void setHowLong(int howLong) {
this.howLong = howLong;
}
}
@ConfigurationProperties(“holoman”)를 통해 본 프로젝트에서 설정하는 프로퍼티 파일에 holoman.* 을 참조해서 가져오고, 그렇게 가져간 프로퍼티를 HolomanConfiguration에서 세팅이 된다.
그럼 본 프로젝트에서는
@Component
public class HolomanRunner implements ApplicationRunner {
@Autowired
Holoman holoman;
@Override
public void run(ApplicationArguments args) throws Exception{
System.out.println(holoman);
}
}
설정은 프로퍼티 파일에서 하고, 주입만 받아서 사용하면 된다.
- 참고 프로퍼티(@ConfigurationProperties 에 해당하는 프로퍼티에 대한) 자동완성 지원을 하려면 선언해주어야 함.
~~~xml
~~~
이걸 의존받지 않으면
holoman.name = 꾸준히 공부를 해야죠.
holeman.
여기서 바로 밑에 리스트가 뜨지 않는다.(자동완성)
@Conditional~~ 굉장히 다양하다
@ConditionalOnMissingBean.. 등등
차차 활용 파트 가면서 정리 예정