dependencies {
implementation 'org.springframework.boot::spring-boot-starter-web'
}
dependencies {
implementation 'org.springframework.boot::spring-boot-starter-web'
implementation 'org.springframework.boot::spring-boot-starter-jetty'
}
TomcatServletWebServerFactory
빈 이름과 충돌을 피하기 위해 이름을 따로 지정@MyAutoConfiguration
public class TomcatWebServerConfig {
@Bean("tomcatWebServerFactory")
public ServletWebServerFactory servrWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
@MyAutoConfiguration
public class JettyWebServerConfig {
@Bean("jettyWebServerFactory")
public ServletWebServerFactory servletWebServerFactory() {
return new JettyServletWebServerFactory();
}
}
tobyspring.config.MyAutoConfiguration.imports
내부에도 jetty 설정을 추가tobyspring.config.autoconfig.DispatcherServletConfig
tobyspring.config.autoconfig.TomcatWebServerConfig
tobyspring.config.autoconfig.JettyWebServerConfig
ServletWebServerFactory
가 존재하기 때문@Conditional
을 사용할 수 있다.@Conditional
은 Condition
인터페이스 구현체 클래스를 엘리먼트로 가진다.@MyAutoConfiguration
@Conditional(JettyWebserverConfig.JettyCondition.class)
public class JettyWebServerConfig {
@Bean("jettyWebServerFactory")
public ServletWebServerFactory servletWebServerFactory() {
return new JettyServletWebServerFactory();
}
// boolean 반환 여부에 따라 빈을 띄우거나 띄우지 않음
static class JettyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return true
}
}
}
TomcatWebServerConfig
에는 반대로 false
를 반환하는 Condition
구현체를 @Conditional
로 등록하면 Jetty 서버가 뜨게 된다.
true
르 반환하면 이전과 똑같은 이유로 애플리케이션이 뜨지 않는다.Tomcat.java
클래스 자체가, Jetty의 경우 Server.java
클래스가 jetty.server 패키지 하위에 존재한다.Spring
에는 ClassUtils
클래스가 존재하는데 이걸 사용해서 특정 클래스가 존재하는지를 알 수 있다.@MyAutoConfiguration
@Conditional(TomcatWebServerConfig.TomcatCondition.class)
public class TomcatWebServerConfig {
@Bean("tomcatWebServerFactory")
public ServletWebServerFactory servrWebServerFactory() {
return new TomcatServletWebServerFactory();
}
static class TomcatCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return ClassUtils.isPresent("org.apache.catalina.startup.Tomcat",
context.getClassLoader());
}
}
}
@MyAutoConfiguration
@Conditional(JettyWebserverConfig.JettyCondition.class)
public class JettyWebServerConfig {
@Bean("jettyWebServerFactory")
public ServletWebServerFactory servletWebServerFactory() {
return new JettyServletWebServerFactory();
}
static class JettyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return ClassUtils.isPresent("org.eclipse.jetty.server.Server",
context.getClassLoader());
}
}
}
dependencies {
implementation 'org.springframework.boot::spring-boot-starter-web' {
exclude group: 'org.springframework.boot', module: 'sppring-boot-starter-tomcat'
}
implementation 'org.springframework.boot::spring-boot-starter-jetty'
}
Conditional
을 메타 어노테이션으로 만들어 사용할 수 있다.
@Rentention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Conditional(MyOnClassCondition.class)
public @interface ConditionalMyOnClass {
String value(); // 있는지 체크할 클래스 이름
}
public class MyOnClassCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> attrs = metadata.getAnnotationAttribute(ConditionalMyOnClass.class());
String value = (String) attrs.get("value");
return ClassUtils.isPresent("value", context.getClassLoader());
}
}
@MyAutoConfiguration
@ConditionalMyOnClass("org.apache.catalina.startup.Tomcat")
public class TomcatWebServerConfig {
@Bean("tomcatWebServerFactory")
public ServletWebServerFactory servrWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
@MyAutoConfiguration
@ConditionalMyOnClass("org.eclipse.jetty.server.Server")
public class JettyWebServerConfig {
@Bean("jettyWebServerFactory")
public ServletWebServerFactory servletWebServerFactory() {
return new JettyServletWebServerFactory();
}
}
tobyspring.helloboot
패키지 하위에 WebServerConfiguration
클래스를 만든다.
@Configuration(proxyBeanMethods = false)
public class WebServerConfiguration {
@Bean
ServletWebServerFacotry customerWebServerFacotry() {
TomcatServletWebServerFactory sf = new TomcatServletWebServerFactory();
sf.setPort(9090);
return sf;
}
}
@ConditionalOnMissingBean
로 이미 동일 타입 빈이 존재하면 뜨지 않도록 설정할 수 있다.
DefaultImportSelecter
를 사용했는데 이는 사용자 구성 정보가 로딩이 된 뒤 자동 구성 정보를 구성한다.@MyAutoConfiguration
@ConditionalMyOnClass("org.apache.catalina.startup.Tomcat")
public class TomcatWebServerConfig {
@Bean("tomcatWebServerFactory")
@ConditionalOnMissingBean
public ServletWebServerFactory servrWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
@Profile
도 @Conditional
애노테이션이다.@Conditional(ProfileCondition.class)
public @interface Profile {
// ...
}
@Conditional
애노테이션과 Condition
을 제공한다.
@ConditionalOnClass
@ConditionalOnMissingClass
@Configuration
클래스 레벨에서 사용하지만 @Bean
메서드에도 적용 가능
@Bean
메서드에만 적용하면 불필요하게 @Configuration
클래스가 빈으로 등록되기에 클래스 레벨 사용을 우선하면 좋다.@ConditionalOnBean
@ConditionalOnMissingBean
@Configuration
클래스 적용 순서가 중요
@Configuration
클래스 레벨의 @ConditionalOnClass
와 @Bean
메서드 레벨의 @ConditionalOnMissingBean
조합이 대표적@ConditionalOnProperty
false
가 아니면 포함 대상이 된다.@ConditionalOnResource
@ConditionalOnWebApplication
@ConditionalOnNotWebApplication
@ConditionalOnExpression