From f9c8550259ca5bd7504ec0b50282e3fab0357be8 Mon Sep 17 00:00:00 2001 From: Basak Date: Mon, 24 Apr 2023 21:36:38 +0900 Subject: [PATCH 1/6] =?UTF-8?q?feat(CH07):=20conditional=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=ED=95=B4=EB=B3=B4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hyeonsik/spring-boot-project/build.gradle | 5 +- .../autoconfig/JettyWebServerConfig.java | 27 +++++++ .../autoconfig/TomcatWebServerConfig.java | 14 +++- ...ingBoot.config.MyAutoConfiguration.imports | 1 + .../tobySpringBoot/study/ConditionalTest.java | 73 +++++++++++++++++++ 5 files changed, 116 insertions(+), 4 deletions(-) create mode 100644 hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/JettyWebServerConfig.java create mode 100644 hyeonsik/spring-boot-project/src/test/java/tobySpringBoot/study/ConditionalTest.java diff --git a/hyeonsik/spring-boot-project/build.gradle b/hyeonsik/spring-boot-project/build.gradle index 301fbd4..bc2f86f 100644 --- a/hyeonsik/spring-boot-project/build.gradle +++ b/hyeonsik/spring-boot-project/build.gradle @@ -13,7 +13,10 @@ repositories { } dependencies { - implementation 'org.springframework.boot:spring-boot-starter-web' + implementation('org.springframework.boot:spring-boot-starter-web') { + exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat' + } + implementation 'org.springframework.boot:spring-boot-starter-jetty' testImplementation 'org.springframework.boot:spring-boot-starter-test' } diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/JettyWebServerConfig.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/JettyWebServerConfig.java new file mode 100644 index 0000000..890f159 --- /dev/null +++ b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/JettyWebServerConfig.java @@ -0,0 +1,27 @@ +package tobySpringBoot.config.autoconfig; + +import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory; +import org.springframework.boot.web.servlet.server.ServletWebServerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.context.annotation.Conditional; +import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.util.ClassUtils; +import tobySpringBoot.config.MyAutoConfiguration; + +@MyAutoConfiguration +@Conditional(JettyWebServerConfig.JettyCondition.class) +public class JettyWebServerConfig { + @Bean("jettyWebServerFactory") // bean name은 기본적으로 method 명을 따라간다. 동일 이름이 있으면 충돌이 날 수 있으니 이름을 구분!! + 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()); + } + } +} diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/TomcatWebServerConfig.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/TomcatWebServerConfig.java index b13035d..60ded6e 100644 --- a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/TomcatWebServerConfig.java +++ b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/TomcatWebServerConfig.java @@ -2,15 +2,23 @@ import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.servlet.server.ServletWebServerFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.*; +import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.util.ClassUtils; import tobySpringBoot.config.MyAutoConfiguration; @MyAutoConfiguration +@Conditional(TomcatWebServerConfig.TomcatCondition.class) public class TomcatWebServerConfig { - @Bean + @Bean("tomcatWebServerFactory") public ServletWebServerFactory servletWebServerFactory() { 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()); + } + } } diff --git a/hyeonsik/spring-boot-project/src/main/resources/META-INF/spring/tobySpringBoot.config.MyAutoConfiguration.imports b/hyeonsik/spring-boot-project/src/main/resources/META-INF/spring/tobySpringBoot.config.MyAutoConfiguration.imports index ea4c6a5..2371367 100644 --- a/hyeonsik/spring-boot-project/src/main/resources/META-INF/spring/tobySpringBoot.config.MyAutoConfiguration.imports +++ b/hyeonsik/spring-boot-project/src/main/resources/META-INF/spring/tobySpringBoot.config.MyAutoConfiguration.imports @@ -1,2 +1,3 @@ tobySpringBoot.config.autoconfig.TomcatWebServerConfig +tobySpringBoot.config.autoconfig.JettyWebServerConfig tobySpringBoot.config.autoconfig.DispatcherServletConfig diff --git a/hyeonsik/spring-boot-project/src/test/java/tobySpringBoot/study/ConditionalTest.java b/hyeonsik/spring-boot-project/src/test/java/tobySpringBoot/study/ConditionalTest.java new file mode 100644 index 0000000..6306909 --- /dev/null +++ b/hyeonsik/spring-boot-project/src/test/java/tobySpringBoot/study/ConditionalTest.java @@ -0,0 +1,73 @@ +package tobySpringBoot.study; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.*; +import org.springframework.core.type.AnnotatedTypeMetadata; + +import java.beans.BeanProperty; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.Map; + +//import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +public class ConditionalTest { + @Test + void conditional() { +// // true +// ApplicationContextRunner contextRunner = new ApplicationContextRunner(); +// contextRunner.withUserConfiguration(Config1.class) +// .run(context -> { +// assertThat(context).hasSingleBean(MyBean.class); +// assertThat(context).hasSingleBean(Config1.class); +// }); +// +// // false +// new ApplicationContextRunner().withUserConfiguration(Config1.class) +// .run(context -> { +// assertThat(context).doesNotHaveBean(MyBean.class); +// assertThat(context).doesNotHaveBean(Config1.class); +// }); + + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + @Conditional(BooleanCondition.class) + @interface BooleanConditional { + boolean value(); + } + + @Configuration + @BooleanConditional(true) + static class Config1 { // <- static으로 선언하면 inner class 처럼 취급되지 않는다. 대신 상위 클래스가 마치 package 역할을 한다. + @Bean + MyBean myBean() { + return new MyBean(); + } + } + + @Configuration + @BooleanConditional(false) + static class Config2 { + @Bean + MyBean myBean() { + return new MyBean(); + } + } + + static class MyBean { + } + + static class BooleanCondition implements Condition { + @Override + public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + Map annotationAttributes = metadata.getAnnotationAttributes(BooleanConditional.class.getName()); + return (Boolean) annotationAttributes.get("value"); + } + } + +} From bacff8777074bf79da3d7d384112403675210adf Mon Sep 17 00:00:00 2001 From: Basak Date: Mon, 24 Apr 2023 22:23:59 +0900 Subject: [PATCH 2/6] =?UTF-8?q?feat(CH07):=20=EC=9E=90=EB=8F=99=20?= =?UTF-8?q?=EA=B5=AC=EC=84=B1=20=EC=A0=95=EB=B3=B4=20=EA=B0=9C=EB=B0=9C?= =?UTF-8?q?=EC=9E=90=EA=B0=80=20=EB=8C=80=EC=B2=B4=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hyeonsik/spring-boot-project/build.gradle | 5 +---- .../config/ConditionalMyOnClass.java | 15 +++++++++++++++ .../config/autoconfig/JettyWebServerConfig.java | 11 ++++------- .../config/autoconfig/TomcatWebServerConfig.java | 12 +++++------- .../learn/WebServerConfiguration.java | 16 ++++++++++++++++ 5 files changed, 41 insertions(+), 18 deletions(-) create mode 100644 hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/ConditionalMyOnClass.java create mode 100644 hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/learn/WebServerConfiguration.java diff --git a/hyeonsik/spring-boot-project/build.gradle b/hyeonsik/spring-boot-project/build.gradle index bc2f86f..5a581b7 100644 --- a/hyeonsik/spring-boot-project/build.gradle +++ b/hyeonsik/spring-boot-project/build.gradle @@ -13,10 +13,7 @@ repositories { } dependencies { - implementation('org.springframework.boot:spring-boot-starter-web') { - exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat' - } - implementation 'org.springframework.boot:spring-boot-starter-jetty' + implementation('org.springframework.boot:spring-boot-starter-web') testImplementation 'org.springframework.boot:spring-boot-starter-test' } diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/ConditionalMyOnClass.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/ConditionalMyOnClass.java new file mode 100644 index 0000000..84bd9dc --- /dev/null +++ b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/ConditionalMyOnClass.java @@ -0,0 +1,15 @@ +package tobySpringBoot.config; + +import org.springframework.context.annotation.Conditional; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD}) +@Conditional(MyOnClassCondition.class) +public @interface ConditionalMyOnClass { + String value(); +} diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/JettyWebServerConfig.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/JettyWebServerConfig.java index 890f159..4ab8f92 100644 --- a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/JettyWebServerConfig.java +++ b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/JettyWebServerConfig.java @@ -1,5 +1,6 @@ package tobySpringBoot.config.autoconfig; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory; import org.springframework.boot.web.servlet.server.ServletWebServerFactory; import org.springframework.context.annotation.Bean; @@ -8,20 +9,16 @@ import org.springframework.context.annotation.Conditional; import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.util.ClassUtils; +import tobySpringBoot.config.ConditionalMyOnClass; import tobySpringBoot.config.MyAutoConfiguration; @MyAutoConfiguration -@Conditional(JettyWebServerConfig.JettyCondition.class) +@ConditionalMyOnClass("org.eclipse.jetty.server.Server") public class JettyWebServerConfig { @Bean("jettyWebServerFactory") // bean name은 기본적으로 method 명을 따라간다. 동일 이름이 있으면 충돌이 날 수 있으니 이름을 구분!! + @ConditionalOnMissingBean 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()); - } - } } diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/TomcatWebServerConfig.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/TomcatWebServerConfig.java index 60ded6e..1203993 100644 --- a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/TomcatWebServerConfig.java +++ b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/TomcatWebServerConfig.java @@ -1,24 +1,22 @@ package tobySpringBoot.config.autoconfig; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.servlet.server.ServletWebServerFactory; import org.springframework.context.annotation.*; import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.util.ClassUtils; +import tobySpringBoot.config.ConditionalMyOnClass; import tobySpringBoot.config.MyAutoConfiguration; @MyAutoConfiguration -@Conditional(TomcatWebServerConfig.TomcatCondition.class) +@ConditionalMyOnClass("org.apache.catalina.startup.Tomcat") public class TomcatWebServerConfig { @Bean("tomcatWebServerFactory") + // @Conditional() + @ConditionalOnMissingBean // 이미 동일한 타입의 빈이 등록되어있는가? 그렇지 않다면 빈으로 등록해줘라! 라는 condition public ServletWebServerFactory servletWebServerFactory() { 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()); - } - } } diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/learn/WebServerConfiguration.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/learn/WebServerConfiguration.java new file mode 100644 index 0000000..28f9379 --- /dev/null +++ b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/learn/WebServerConfiguration.java @@ -0,0 +1,16 @@ +package tobySpringBoot.learn; + +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; +import org.springframework.boot.web.servlet.server.ServletWebServerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +public class WebServerConfiguration { + @Bean + ServletWebServerFactory customerWebServerFactory() { + TomcatServletWebServerFactory serverFactory = new TomcatServletWebServerFactory(); + serverFactory.setPort(9090); + return serverFactory; + } +} From 1b9c2a4ed716ad4b26d290fdb9f1fcc064c3635d Mon Sep 17 00:00:00 2001 From: Basak Date: Mon, 24 Apr 2023 22:24:04 +0900 Subject: [PATCH 3/6] =?UTF-8?q?feat(CH07):=20=EC=9E=90=EB=8F=99=20?= =?UTF-8?q?=EA=B5=AC=EC=84=B1=20=EC=A0=95=EB=B3=B4=20=EA=B0=9C=EB=B0=9C?= =?UTF-8?q?=EC=9E=90=EA=B0=80=20=EB=8C=80=EC=B2=B4=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/MyOnClassCondition.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/MyOnClassCondition.java diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/MyOnClassCondition.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/MyOnClassCondition.java new file mode 100644 index 0000000..41053bd --- /dev/null +++ b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/MyOnClassCondition.java @@ -0,0 +1,17 @@ +package tobySpringBoot.config; + +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.util.ClassUtils; + +import java.util.Map; + +public class MyOnClassCondition implements Condition { + @Override + public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + Map annotationAttributes = metadata.getAnnotationAttributes(ConditionalMyOnClass.class.getName()); + String value = (String) annotationAttributes.get("value"); + return ClassUtils.isPresent(value, context.getClassLoader()); + } +} From 3df5e291ef834ac7362fb8ecf38dfc774e836206 Mon Sep 17 00:00:00 2001 From: Basak Date: Tue, 25 Apr 2023 02:08:05 +0900 Subject: [PATCH 4/6] =?UTF-8?q?feat(CH08):=20environment=20properties=20?= =?UTF-8?q?=ED=99=9C=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../autoconfig/PropertyPlaceholderConfig.java | 13 +++++++++++++ .../config/autoconfig/TomcatWebServerConfig.java | 9 ++++++++- .../tobySpringBoot/learn/LearnApplication.java | 10 +++++++--- .../learn/WebServerConfiguration.java | 16 ---------------- ...SpringBoot.config.MyAutoConfiguration.imports | 1 + .../src/main/resources/application.properties | 2 +- 6 files changed, 30 insertions(+), 21 deletions(-) create mode 100644 hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/PropertyPlaceholderConfig.java delete mode 100644 hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/learn/WebServerConfiguration.java diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/PropertyPlaceholderConfig.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/PropertyPlaceholderConfig.java new file mode 100644 index 0000000..fa16075 --- /dev/null +++ b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/PropertyPlaceholderConfig.java @@ -0,0 +1,13 @@ +package tobySpringBoot.config.autoconfig; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; +import tobySpringBoot.config.MyAutoConfiguration; + +@MyAutoConfiguration +public class PropertyPlaceholderConfig { + @Bean + PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { + return new PropertySourcesPlaceholderConfigurer(); + } +} diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/TomcatWebServerConfig.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/TomcatWebServerConfig.java index 1203993..6531c58 100644 --- a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/TomcatWebServerConfig.java +++ b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/TomcatWebServerConfig.java @@ -1,9 +1,11 @@ package tobySpringBoot.config.autoconfig; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.servlet.server.ServletWebServerFactory; import org.springframework.context.annotation.*; +import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.util.ClassUtils; import tobySpringBoot.config.ConditionalMyOnClass; @@ -12,11 +14,16 @@ @MyAutoConfiguration @ConditionalMyOnClass("org.apache.catalina.startup.Tomcat") public class TomcatWebServerConfig { + @Value("${contextPath}") // BeanFactoryPostProcessor 라는 후처리 로직(이것도 Bean임)이 동작을 처리해준다! + String contextPath; + @Bean("tomcatWebServerFactory") // @Conditional() @ConditionalOnMissingBean // 이미 동일한 타입의 빈이 등록되어있는가? 그렇지 않다면 빈으로 등록해줘라! 라는 condition public ServletWebServerFactory servletWebServerFactory() { - return new TomcatServletWebServerFactory(); + TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); + factory.setContextPath(this.contextPath); + return factory; } } diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/learn/LearnApplication.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/learn/LearnApplication.java index deddf8a..3003188 100644 --- a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/learn/LearnApplication.java +++ b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/learn/LearnApplication.java @@ -1,10 +1,14 @@ package tobySpringBoot.learn; +import org.springframework.boot.ApplicationRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.core.env.Environment; import tobySpringBoot.config.MySpringBootApplication; @MySpringBootApplication public class LearnApplication { - public static void main(String[] args) { - MySpringApplication.run(LearnApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(LearnApplication.class, args); + } } diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/learn/WebServerConfiguration.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/learn/WebServerConfiguration.java deleted file mode 100644 index 28f9379..0000000 --- a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/learn/WebServerConfiguration.java +++ /dev/null @@ -1,16 +0,0 @@ -package tobySpringBoot.learn; - -import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; -import org.springframework.boot.web.servlet.server.ServletWebServerFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration(proxyBeanMethods = false) -public class WebServerConfiguration { - @Bean - ServletWebServerFactory customerWebServerFactory() { - TomcatServletWebServerFactory serverFactory = new TomcatServletWebServerFactory(); - serverFactory.setPort(9090); - return serverFactory; - } -} diff --git a/hyeonsik/spring-boot-project/src/main/resources/META-INF/spring/tobySpringBoot.config.MyAutoConfiguration.imports b/hyeonsik/spring-boot-project/src/main/resources/META-INF/spring/tobySpringBoot.config.MyAutoConfiguration.imports index 2371367..cde18ed 100644 --- a/hyeonsik/spring-boot-project/src/main/resources/META-INF/spring/tobySpringBoot.config.MyAutoConfiguration.imports +++ b/hyeonsik/spring-boot-project/src/main/resources/META-INF/spring/tobySpringBoot.config.MyAutoConfiguration.imports @@ -1,3 +1,4 @@ +tobySpringBoot.config.autoconfig.PropertyPlaceholderConfig tobySpringBoot.config.autoconfig.TomcatWebServerConfig tobySpringBoot.config.autoconfig.JettyWebServerConfig tobySpringBoot.config.autoconfig.DispatcherServletConfig diff --git a/hyeonsik/spring-boot-project/src/main/resources/application.properties b/hyeonsik/spring-boot-project/src/main/resources/application.properties index 8b13789..74d79de 100644 --- a/hyeonsik/spring-boot-project/src/main/resources/application.properties +++ b/hyeonsik/spring-boot-project/src/main/resources/application.properties @@ -1 +1 @@ - +contextPath=/app From c81efac9d7e2428d1fc058e5df9f348680fecfbf Mon Sep 17 00:00:00 2001 From: Basak Date: Tue, 25 Apr 2023 13:10:34 +0900 Subject: [PATCH 5/6] =?UTF-8?q?feat(CH08):=20properties=20data=20holder=20?= =?UTF-8?q?class=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../autoconfig/ServerPorpertiesConfig.java | 14 ++++++++++ .../config/autoconfig/ServerProperties.java | 28 +++++++++++++++++++ .../autoconfig/TomcatWebServerConfig.java | 12 ++++---- ...ingBoot.config.MyAutoConfiguration.imports | 1 + .../src/main/resources/application.properties | 1 + 5 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/ServerPorpertiesConfig.java create mode 100644 hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/ServerProperties.java diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/ServerPorpertiesConfig.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/ServerPorpertiesConfig.java new file mode 100644 index 0000000..b548cd2 --- /dev/null +++ b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/ServerPorpertiesConfig.java @@ -0,0 +1,14 @@ +package tobySpringBoot.config.autoconfig; + +import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.context.annotation.Bean; +import org.springframework.core.env.Environment; +import tobySpringBoot.config.MyAutoConfiguration; + +@MyAutoConfiguration +public class ServerPorpertiesConfig { + @Bean + public ServerProperties serverProperties(Environment env) { + return Binder.get(env).bind("", ServerProperties.class).get(); + } +} diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/ServerProperties.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/ServerProperties.java new file mode 100644 index 0000000..a25507a --- /dev/null +++ b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/ServerProperties.java @@ -0,0 +1,28 @@ +package tobySpringBoot.config.autoconfig; + +import org.springframework.beans.factory.annotation.Value; + +// 그저 데이터를 가지고 있는 데이터 홀더 클래스임 -> 그러니 그냥 게터세터로 +public class ServerProperties { + @Value("${contextPath}") // BeanFactoryPostProcessor 라는 후처리 로직(이것도 Bean임)이 동작을 처리해준다! + private String contextPath; + + @Value("${port:8080}") // port가 없을경우 :뒤에 있는 8080을 기본값으로 사용한다. + private int port; + + public String getContextPath() { + return contextPath; + } + + public void setContextPath(String contextPath) { + this.contextPath = contextPath; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } +} diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/TomcatWebServerConfig.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/TomcatWebServerConfig.java index 6531c58..c6761a4 100644 --- a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/TomcatWebServerConfig.java +++ b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/TomcatWebServerConfig.java @@ -6,24 +6,22 @@ import org.springframework.boot.web.servlet.server.ServletWebServerFactory; import org.springframework.context.annotation.*; import org.springframework.core.env.Environment; -import org.springframework.core.type.AnnotatedTypeMetadata; -import org.springframework.util.ClassUtils; import tobySpringBoot.config.ConditionalMyOnClass; import tobySpringBoot.config.MyAutoConfiguration; @MyAutoConfiguration @ConditionalMyOnClass("org.apache.catalina.startup.Tomcat") public class TomcatWebServerConfig { - @Value("${contextPath}") // BeanFactoryPostProcessor 라는 후처리 로직(이것도 Bean임)이 동작을 처리해준다! - String contextPath; + @Bean("tomcatWebServerFactory") - // @Conditional() @ConditionalOnMissingBean // 이미 동일한 타입의 빈이 등록되어있는가? 그렇지 않다면 빈으로 등록해줘라! 라는 condition - public ServletWebServerFactory servletWebServerFactory() { + public ServletWebServerFactory servletWebServerFactory(ServerProperties properties) { TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); - factory.setContextPath(this.contextPath); + factory.setContextPath(properties.getContextPath()); + factory.setPort(properties.getPort()); return factory; } + } diff --git a/hyeonsik/spring-boot-project/src/main/resources/META-INF/spring/tobySpringBoot.config.MyAutoConfiguration.imports b/hyeonsik/spring-boot-project/src/main/resources/META-INF/spring/tobySpringBoot.config.MyAutoConfiguration.imports index cde18ed..0e3c360 100644 --- a/hyeonsik/spring-boot-project/src/main/resources/META-INF/spring/tobySpringBoot.config.MyAutoConfiguration.imports +++ b/hyeonsik/spring-boot-project/src/main/resources/META-INF/spring/tobySpringBoot.config.MyAutoConfiguration.imports @@ -1,4 +1,5 @@ tobySpringBoot.config.autoconfig.PropertyPlaceholderConfig +tobySpringBoot.config.autoconfig.ServerPorpertiesConfig tobySpringBoot.config.autoconfig.TomcatWebServerConfig tobySpringBoot.config.autoconfig.JettyWebServerConfig tobySpringBoot.config.autoconfig.DispatcherServletConfig diff --git a/hyeonsik/spring-boot-project/src/main/resources/application.properties b/hyeonsik/spring-boot-project/src/main/resources/application.properties index 74d79de..11d140f 100644 --- a/hyeonsik/spring-boot-project/src/main/resources/application.properties +++ b/hyeonsik/spring-boot-project/src/main/resources/application.properties @@ -1 +1,2 @@ contextPath=/app +port=9090 From fb06121e3e7c0e96a81a8d0b9d9d58330f6bc803 Mon Sep 17 00:00:00 2001 From: Basak Date: Tue, 25 Apr 2023 14:46:08 +0900 Subject: [PATCH 6/6] =?UTF-8?q?feat(CH08):=20EnableMyConfigurationProperti?= =?UTF-8?q?es=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EnableMyConfigurationProperties.java | 15 +++++++++ .../config/MyConfigurationProperties.java | 15 +++++++++ ...ConfigurationPropertiesImportSelector.java | 14 ++++++++ .../autoconfig/PropertyPlaceholderConfig.java | 1 + .../PropertyPostProcessorConfig.java | 32 +++++++++++++++++++ .../autoconfig/ServerPorpertiesConfig.java | 14 -------- .../config/autoconfig/ServerProperties.java | 4 +-- .../autoconfig/TomcatWebServerConfig.java | 7 ++-- ...ingBoot.config.MyAutoConfiguration.imports | 2 +- .../src/main/resources/application.properties | 4 +-- 10 files changed, 84 insertions(+), 24 deletions(-) create mode 100644 hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/EnableMyConfigurationProperties.java create mode 100644 hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/MyConfigurationProperties.java create mode 100644 hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/MyConfigurationPropertiesImportSelector.java create mode 100644 hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/PropertyPostProcessorConfig.java delete mode 100644 hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/ServerPorpertiesConfig.java diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/EnableMyConfigurationProperties.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/EnableMyConfigurationProperties.java new file mode 100644 index 0000000..fedb529 --- /dev/null +++ b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/EnableMyConfigurationProperties.java @@ -0,0 +1,15 @@ +package tobySpringBoot.config; + +import org.springframework.context.annotation.Import; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Import(MyConfigurationPropertiesImportSelector.class) +public @interface EnableMyConfigurationProperties { + Class value(); +} diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/MyConfigurationProperties.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/MyConfigurationProperties.java new file mode 100644 index 0000000..b04a32e --- /dev/null +++ b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/MyConfigurationProperties.java @@ -0,0 +1,15 @@ +package tobySpringBoot.config; + +import org.springframework.stereotype.Component; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) // marking하는 역할이므로 +@Component +public @interface MyConfigurationProperties { + String prefix(); +} diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/MyConfigurationPropertiesImportSelector.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/MyConfigurationPropertiesImportSelector.java new file mode 100644 index 0000000..5e5cc0c --- /dev/null +++ b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/MyConfigurationPropertiesImportSelector.java @@ -0,0 +1,14 @@ +package tobySpringBoot.config; + +import org.springframework.context.annotation.DeferredImportSelector; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.util.MultiValueMap; + +public class MyConfigurationPropertiesImportSelector implements DeferredImportSelector { + @Override + public String[] selectImports(AnnotationMetadata importingClassMetadata) { + MultiValueMap attr = importingClassMetadata.getAllAnnotationAttributes(EnableMyConfigurationProperties.class.getName()); + Class propertyClass = (Class) attr.getFirst("value"); + return new String[] {propertyClass.getName() }; + } +} diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/PropertyPlaceholderConfig.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/PropertyPlaceholderConfig.java index fa16075..0ce61f2 100644 --- a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/PropertyPlaceholderConfig.java +++ b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/PropertyPlaceholderConfig.java @@ -3,6 +3,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import tobySpringBoot.config.MyAutoConfiguration; +import tobySpringBoot.config.MyConfigurationProperties; @MyAutoConfiguration public class PropertyPlaceholderConfig { diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/PropertyPostProcessorConfig.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/PropertyPostProcessorConfig.java new file mode 100644 index 0000000..bbc8139 --- /dev/null +++ b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/PropertyPostProcessorConfig.java @@ -0,0 +1,32 @@ +package tobySpringBoot.config.autoconfig; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.context.annotation.Bean; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.env.Environment; +import tobySpringBoot.config.MyAutoConfiguration; +import tobySpringBoot.config.MyConfigurationProperties; + +import java.util.Map; + +@MyAutoConfiguration +public class PropertyPostProcessorConfig { + @Bean + BeanPostProcessor propertyPostProcessor(Environment env) { + return new BeanPostProcessor() { + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + // 우리가 만든 marker annotation만 이를 적용할 것이다. (MyConfigurationProperties) + MyConfigurationProperties annotation = AnnotationUtils.findAnnotation(bean.getClass(), MyConfigurationProperties.class); + if (annotation == null) return bean; + + Map attrs = AnnotationUtils.getAnnotationAttributes(annotation); // 애노테이션에 있는 모든 value를 찾는다. + String prefix = (String) attrs.get("prefix"); // 그 중 prefix 로 시작하는 녀석을 확인한다. + + return Binder.get(env).bindOrCreate(prefix, bean.getClass()); + } + }; + } +} diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/ServerPorpertiesConfig.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/ServerPorpertiesConfig.java deleted file mode 100644 index b548cd2..0000000 --- a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/ServerPorpertiesConfig.java +++ /dev/null @@ -1,14 +0,0 @@ -package tobySpringBoot.config.autoconfig; - -import org.springframework.boot.context.properties.bind.Binder; -import org.springframework.context.annotation.Bean; -import org.springframework.core.env.Environment; -import tobySpringBoot.config.MyAutoConfiguration; - -@MyAutoConfiguration -public class ServerPorpertiesConfig { - @Bean - public ServerProperties serverProperties(Environment env) { - return Binder.get(env).bind("", ServerProperties.class).get(); - } -} diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/ServerProperties.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/ServerProperties.java index a25507a..5d350c3 100644 --- a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/ServerProperties.java +++ b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/ServerProperties.java @@ -1,13 +1,13 @@ package tobySpringBoot.config.autoconfig; import org.springframework.beans.factory.annotation.Value; +import tobySpringBoot.config.MyConfigurationProperties; // 그저 데이터를 가지고 있는 데이터 홀더 클래스임 -> 그러니 그냥 게터세터로 +@MyConfigurationProperties(prefix = "server") public class ServerProperties { - @Value("${contextPath}") // BeanFactoryPostProcessor 라는 후처리 로직(이것도 Bean임)이 동작을 처리해준다! private String contextPath; - @Value("${port:8080}") // port가 없을경우 :뒤에 있는 8080을 기본값으로 사용한다. private int port; public String getContextPath() { diff --git a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/TomcatWebServerConfig.java b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/TomcatWebServerConfig.java index c6761a4..a13c14b 100644 --- a/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/TomcatWebServerConfig.java +++ b/hyeonsik/spring-boot-project/src/main/java/tobySpringBoot/config/autoconfig/TomcatWebServerConfig.java @@ -1,19 +1,17 @@ package tobySpringBoot.config.autoconfig; -import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.servlet.server.ServletWebServerFactory; import org.springframework.context.annotation.*; -import org.springframework.core.env.Environment; import tobySpringBoot.config.ConditionalMyOnClass; +import tobySpringBoot.config.EnableMyConfigurationProperties; import tobySpringBoot.config.MyAutoConfiguration; @MyAutoConfiguration @ConditionalMyOnClass("org.apache.catalina.startup.Tomcat") +@EnableMyConfigurationProperties(ServerProperties.class) public class TomcatWebServerConfig { - - @Bean("tomcatWebServerFactory") @ConditionalOnMissingBean // 이미 동일한 타입의 빈이 등록되어있는가? 그렇지 않다면 빈으로 등록해줘라! 라는 condition public ServletWebServerFactory servletWebServerFactory(ServerProperties properties) { @@ -23,5 +21,4 @@ public ServletWebServerFactory servletWebServerFactory(ServerProperties properti return factory; } - } diff --git a/hyeonsik/spring-boot-project/src/main/resources/META-INF/spring/tobySpringBoot.config.MyAutoConfiguration.imports b/hyeonsik/spring-boot-project/src/main/resources/META-INF/spring/tobySpringBoot.config.MyAutoConfiguration.imports index 0e3c360..b14fc02 100644 --- a/hyeonsik/spring-boot-project/src/main/resources/META-INF/spring/tobySpringBoot.config.MyAutoConfiguration.imports +++ b/hyeonsik/spring-boot-project/src/main/resources/META-INF/spring/tobySpringBoot.config.MyAutoConfiguration.imports @@ -1,5 +1,5 @@ tobySpringBoot.config.autoconfig.PropertyPlaceholderConfig -tobySpringBoot.config.autoconfig.ServerPorpertiesConfig +tobySpringBoot.config.autoconfig.PropertyPostProcessorConfig tobySpringBoot.config.autoconfig.TomcatWebServerConfig tobySpringBoot.config.autoconfig.JettyWebServerConfig tobySpringBoot.config.autoconfig.DispatcherServletConfig diff --git a/hyeonsik/spring-boot-project/src/main/resources/application.properties b/hyeonsik/spring-boot-project/src/main/resources/application.properties index 11d140f..fb34891 100644 --- a/hyeonsik/spring-boot-project/src/main/resources/application.properties +++ b/hyeonsik/spring-boot-project/src/main/resources/application.properties @@ -1,2 +1,2 @@ -contextPath=/app -port=9090 +server.contextPath=/app +server.port=9090