Bean ๋ฑ๋ก์ ๋ํ ์ฌ๊ณ
SpringBoot์์ Bean์ ๋ฑ๋กํ๋ ๋ฐฉ๋ฒ์ ๋ฌด์์ด ์์๊น. 1. ํด๋์ค์ ์ง์ @Component ์ ๋ ธํ ์ด์ ์ ์ฌ์ฉํ๋ ๋ฐฉ์ 2. @Configuration ์ ๋ ธํ ์ด์ ์ ํ์ฉํด @Bean ๋ฑ๋กํ๋ ๋ฐฉ์ ์ 2๊ฐ์ง ๋ฐฉ์์ด ๋ณดํธ์ ์ด๋ค.
sweeeetgoguma.tistory.com
์ด์ ํฌ์คํธ์ ์ด์ด ์ด๋ฒ์๋ Spring Framework์ ์๋! Conditional ์๋ฆฌ์ฆ๋ฅผ ํ์ฉํ Bean ๋ฑ๋ก์ ๋ํด ์์ฑํด๋ณด๋ ค ํ๋ค.
์์ํ๋ฉฐ
์ฌํด ์ด๋ถํฐ ์ ๋ง ์ผ์ด ๋ง๋ค. ๋ญ.. ๊ฐ ์๋ก ์์ฌ๊ฐ๋ค. ๊ธฐ์ ์ ๋ฐฑ๋ก๊ทธ๋ง ๋ช ์ญ ๊ฐ ์ ๋ ๋๋ ๋ฏํ๋ค.
๋ค์ผ๋ก ๊ธฐ์ ๊ณผ์ ์ ๋ถ์ฑ๋ ๋ง์ด ๋์ด๋ฌ๋ค. ๋น์ฅ ํด๊ฒฐํด์ผ ํ๋ ๊ธํ ๊ฑด์ ์๋์ง๋ง, ์ด๋ฒ ์ฃผ๋ ๋คํํ ์๊ฐ์ด ์ฌ์ ๋ก์ด ๊ฒ ๊ฐ์ ํํ์ด ๊ฐ์ ์ ํ๋ค. (๋ธ๋ก๊น ํ ์์ค๊ฐ ๋ง์ด ๋์ด๋ฌ์ง๋ง! ์๊ฐ์ด ์ฌ์ ๋กญ์ง ์์ ๋ฐํ ๋๊ธฐ ์ค~)
์ฃผ๋ ฅ์ผ๋ก ๋งก๊ณ ์๋ ํ๋ก์ ํธ๋ ๋ฉํฐ ๋ชจ๋ํ ๋ฉํฐ bootjar๋ฅผ ๊ฐ์ง๋ ํ๋ก์ ํธ์ด๋ค.
api, consumer, batch ๋ฑ์ ๋ชจ๋๋ก ๊ด๋ฆฌํ๋ ์ ํ๋ฆฌ์ผ์ด์ ๋ค์ด ์๋๋ฐ, ์๊ตฌ์ฌํญ์ ๋ฐ๋ผ ์ฝ๋ ์์ด ์ ์ฐจ ๋์ด๋๊ฒ ๋์ด ๋ค์ ํ๋ฒ ์ ๋ง ํ์ํ Bean๋ง์ ๋ฑ๋กํด์ผ ๋๊ฒ ๋ค๋ ์๊ฐ์ด ์คํ๋ฆฐํธ๋ฅผ ์งํํ๋ฉฐ ๋ค์๋ค. ์ด ์คํ๋ฆฐํธ๊ฐ ๋๋๊ณ ๋ฐฐํฌํ๋ฉด, ๊ธฐํ์ฝ ๊ฐ์ ํด ๋ณด๋ฆฌ๋ผ!!
๊ทธ๋์ ์ด์ ๋ถํฐ SpringFramework์ Condition์ ์ ๊ทน ํ์ฉํ์ฌ ๊ฐ์ ์์ ์ ํ๋ค.
V1 ๋ฒ์ ์ ๋นํด ์ข ๋ ์์ฝ๊ฒ, ์ ๋ ธํ ์ด์ ๊ธฐ๋ฐ์ผ๋ก ์กฐ๊ฑด๋ถ Bean ๋ฑ๋ก์ ํ ์ ์๊ฒ ใ ใ
๊ทธ ๊ณผ์ ๊ณผ ๊ฒฐ๊ณผ๋ฅผ ํ๋ฒ ๊ณต์ ํด๋ณด๋ ค ํ๋ค.
Condition, Conditional Configuration์ ์๋
์๋ ์์ ๋ฉํฐ ๋ชจ๋๋ค์ ์ดํด๋ณด์.
- api (BootJar)
- batch (BootJar)
- application
- core
- infrastructure
- consumer (BootJar)
ํ์ฌ ํ๋ก์ ํธ์ ๊ตฌ์กฐ์ด๋ค.
core๋ ๋๋ฉ์ธ ๋ฐ ๊ด๋ จ ๋น์ฆ๋์ค, ๊ณง ์์ POJO์ public interface๋ฅผ ๊ฐ์ง๋ค.
application ์ Use Case๋ฅผ ๋ค๋ฃฌ๋ค.
infrastructure์์ ๊ฐ์ข ์ธ๋ถ ์ค์ ๊ณผ public interface์ ๋ํ ๊ตฌํ์ฒด๋ฅผ ๋ด๋นํ๋ ๋ชจ๋์ธ๋ฐ, ์กฐ๊ฑด๋ถ bean ๋ฑ๋ก์ด ํ์ํ ๋ ์์ด๋ค.
์ฐ๋ฆฌ ํ์์ ๋ด๋นํ๋ ํ๋ก์ ํธ๋ ์ต์ 2, 3๊ฐ์ DB๋ฅผ ๋ฌผ๊ฒ ๋๋๋ฐ, ์ด๋ฅผ auto configuration ํํ๋ก ๋ชจ๋ BootJar์์ Bean ๋ก๋๋์ด ์ฌ์ฉ ์ค์ด์๋ค.
ํ๋ก์ ํธ๊ฐ ์ปค์ง๋ฉด์ ์์ฑํ๋ ํ ์ด๋ธ, ๊ทธ๋ฆฌ๊ณ infra saas, ์ธ๋ถ http Client ์ค์ ๋ฑ์ด ๋ง์์ง๋ฉด์ ํน์ BootJar์์ ๋ถํ์ํ, ์ ํํ๋ ๋ชฐ๋ผ๋ ๋๋ Bean๋ค๋ ๋น๋๋์๋ค.
์ผ๋จ ํ์ํ DB Dao Bean๋ถํฐ ๋ถ๋ฆฌํ๊ฒ ๋ค.
SpringFramework์์ ์ ๊ณตํ๋ interface ์ค Conditional์ด๋ผ๋ ์ ๋ ธํ ์ด์ ์ด ์๋ค.
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class<? extends Condition>[] value();
}
์ด ์ ๋ ธํ ์ด์ ์ Condition interface๋ฅผ ์์ํ๋ value ์์ฑ์ ๊ฐ๋๋ฐ, ์ด๋ Functional interface์ด๋ค.
@FunctionalInterface
public interface Condition {
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
์ด๋ฅผ ๋ด๊ฐ ์ํ๋ Bean ๋ฑ๋ก ํํ์ ์๋ง๊ฒ ๊ตฌํํ์ฌ Conditional ์ ๋ ธํ ์ด์ ์ ์ ๊ณตํ๋ฉด ๋ ๊ฒ์ด๋ค.
Custom annotation
์กฐ๊ฑด๋ถ Bean ๋ฑ๋ก์ ์ฝ๊ฒ ํ๊ธฐ ์ํด ์ปค์คํ ์ ๋ ธํ ์ด์ ์ ๋ง๋ค์๋ค.
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@Conditional(ApplicationTypeCondition::class)
annotation class ConditionalOnApplicationType(
vararg val types: String,
val matchIfMissing: Boolean = false,
)
์์ ๊ฐ์ด ์์ฑ์ ํ๊ณ , Conditional ์ ๋ ธํ ์ด์ ์์ฑ์ผ๋ก ์ปค์คํ condition์ ์ง์ ํ๊ธฐ ์ํด ์๋์ ๊ฐ์ class๋ฅผ ๊ตฌํํ๋ค.
class ApplicationTypeCondition : Condition {
override fun matches(
context: ConditionContext,
metadata: AnnotatedTypeMetadata,
): Boolean {
val applicationType = context.environment.getProperty("application.type")
val attributes =
metadata.getAnnotationAttributes(
ConditionalOnApplicationType::class.java.name,
)
val types = attributes?.get("types") as Array<*>?
val matchIfMissing = attributes?.get("matchIfMissing") as Boolean? ?: false
return when {
applicationType == null -> matchIfMissing
types == null -> matchIfMissing
else -> types.contains(applicationType)
}
}
}
์ต์ข ์ฌ์ฉ ํํ๋ ์๋์ ๊ฐ๋ค.
@Component
@ConditionalOnApplicationType("api", "consumer")
class DBBusinessReader(
private val jpaDao: JpaBusinessesDao,
) : BusinessReader {
// ...
}
// ์๋์ ๊ฐ์ด configuration ์๋ ์ฌ์ฉ ๊ฐ๋ฅ
@Configuration
@ConditionalOnApplicationType("api", "batch", "consumer")
@EnableJpaRepositories(
basePackages = ["infra.db.apple"],
entityManagerFactoryRef = APPLE_ENTITY_MANAGER_FACTORY,
transactionManagerRef = APPLE_JPA_TRANSACTION_MANAGER
)
class AppleDatabaseConfig : DatabaseConfigurationBase("apple") {
// ...
}
์คํํ๋ BootJar์ ํ๋กํผํฐ๋ฅผ ์ฝ์ด type ์ ์ป๊ณ , ๊ทธ type ๊ณผ ์์ฑ์ด ์ผ์นํ๋ฉด Bean ๋ฑ๋ก์ ํ๋ ๊ฐ๋จํ ํํ์ด๋ค.
BootJar ์ type์ ํํ๋ ์๋์ ๊ฐ์ด application.yml ์ ํ๋กํผํฐ๋ก ์ค์ ํ๋ฉด ๋๋ค.
application:
type: api
๊ทธ๋ผ ์ค์ ๋ก ์ง์ ํ type ๋ณ ์ ํ๋ฆฌ์ผ์ด์ ์คํ ์, ์กฐ๊ฑด๋ถ๋ก Bean ๋ฑ๋ก์ด ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
๊ธฐ์กด์๋ ๊ฐ ๋ชจ๋ ๋ณ configuration ํ์ผ์ ์ง์ Bean ๋ฑ๋ก์ ํ๋๋ฐ, ์ด๋ ๊ฒ ํ์ ๋ ์ค๋ณต ๋๋ ์ฝ๋๋ค์ด ์๊ฒผ๋ค.
์ด ์ปค์คํ ์ ํตํด ํธ๋ฆฌํ๊ฒ ์ ๋ ธํ ์ด์ ํํ๋ก ์กฐ๊ฑด๋ถ Bean ๋ฑ๋ก์ ์ฝ๊ฒ ์งํํ ์ ์๊ฒ ๋์๋ค.
๋ง์น๋ฉฐ
๊ฐ๋ฐํ๋ฉฐ ํญ์ ์๊ฐ์ ๋ง์ด ํ๋ ํธ์ธ๋ฐ, ํนํ ์ฑ ์์ ๋ช ํํ ํ๋ ค๋ ํธ์ด๋ค.
์ฑ ์์ ๋ง๊ฒ ๋ฐฐ์นํ๊ณ ์ง์ ํ๋ ๊ฒ์ด ๊ฒฐ๊ตญ ์ ์ง๋ณด์๋ฅผ ์ฝ๊ฒ ํ๊ธฐ ๋๋ฌธ์ด๋ค.
์ด๋ป๊ฒ ํ๋ฉด ์ข ๋ ์ฝ๊ณ , ๊ฐํธํ๊ฒ ํ ์ ์์๊น๋ ์๊ฐ์ ๋งค๋ฒ ํ๋๋ฐ ํผ์ ํ๋ ๊ฒ์ด ์๋ ๊ฒฐ๊ตญ ์ฝ๋๋ ๊ณต์ ๋๊ธฐ์, ๋จ ๋ณด๊ธฐ ํธํ๊ฒ ๋ ์ ๊ฒฝ์ ์ฐ๊ฒ ๋๋ ๊ฒ ๊ฐ๋ค.
๋ฉํฐ ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์กฐ์ ํ๋ก์ ํธ์์ Spring์ ํต์ฌ์ธ Ioc๋ฅผ ๋ ์ฑ ์์ ๋ง๊ฒ ํ์ฉํ๋ ๊ฒ๋ ๊ฒฐ๊ตญ ๋ง์ฐฌ๊ฐ์ง๋ ์๊ฐ์ด ๋ ๋ค.
์ฌ์ฉํ์ง ์๋ ์์กด์ฑ์ ๊ทธ๋๋ก ๋ฌผ๊ณ ์ฌ๋ผ๊ฐ ํ์๊ฐ ์๊ธฐ ๋๋ฌธ์ด๋ค.
์ข ๋ ๊น๋ํ๊ฒ, ๊ทธ๋ฆฌ๊ณ ์์ฑ๋ ์๊ฒ application ๊ตฌ์กฐ๋ฅผ ์ก์๋๊ฐ๋ ๋ฐ๊ฑฐ๋ฆ์ด ๋์์ผ๋ฉด ์ข๊ฒ ๋ค!