Loading...
Spring Framework Reference Documentation 7.0.2의 Composing Java-based Configurations의 한국어 번역본입니다.
아래의 경우에 피드백에서 신고해주신다면 반영하겠습니다.
감사합니다 :)
Spring의 Java 기반 설정 기능은 어노테이션을 구성할 수 있게 해 주며, 이를 통해 설정의 복잡성을 줄일 수 있습니다.
@Import AnnotationSpring XML 파일 내에서 설정을 모듈화하기 위해 <import/> 요소를 사용하는 것과
마찬가지로, @Import 어노테이션을 사용하면 다음 예제에서 보듯이 다른 설정 클래스으로부터
@Bean 정의를 로딩할 수 있습니다:
1@Configuration 2public class ConfigA { 3 4 @Bean 5 public A a() { 6 return new A(); 7 } 8} 9 10@Configuration 11@Import(ConfigA.class) 12public class ConfigB { 13 14 @Bean 15 public B b() { 16 return new B(); 17 } 18}
1@Configuration 2class ConfigA { 3 4 @Bean 5 fun a() = A() 6} 7 8@Configuration 9@Import(ConfigA::class) 10class ConfigB { 11 12 @Bean 13 fun b() = B() 14}
이제 컨텍스트를 인스턴스화할 때 ConfigA.class와 ConfigB.class 둘 다를 지정할 필요 없이,
다음 예제에서 보듯이 명시적으로 제공해야 하는 것은 ConfigB만이면 됩니다:
1public static void main(String[] args) { 2 ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class); 3 4 // now both beans A and B will be available... 5 A a = ctx.getBean(A.class); 6 B b = ctx.getBean(B.class); 7}
1import org.springframework.beans.factory.getBean 2 3fun main() { 4 val ctx = AnnotationConfigApplicationContext(ConfigB::class.java) 5 6 // now both beans A and B will be available... 7 val a = ctx.getBean<A>() 8 val b = ctx.getBean<B>() 9}
이 접근 방식은 컨테이너 인스턴스화를 단순화합니다. 생성 중에 잠재적으로 많은 수의
@Configuration 클래스를 기억해야 하는 대신, 하나의 클래스만 다루면 되기 때문입니다.
Spring Framework 4.2부터,
@Import는 일반 컴포넌트 클래스에 대한 참조도 지원하며,<br>이는AnnotationConfigApplicationContext.register메서드와 유사합니다.<br>이는 몇 개의 설정 클래스를 진입점으로 사용하여 모든 컴포넌트를 명시적으로<br>정의함으로써 컴포넌트 스캐닝을 피하고자 할 때 특히 유용합니다.
@Bean Definitions앞의 예제는 동작하지만 단순합니다. 대부분의 실제 시나리오에서 빈은 설정 클래스 간에
서로에 대한 의존성을 가집니다. XML을 사용할 때는 컴파일러가 관여하지 않기 때문에
문제가 되지 않으며, ref="someBean"을 선언하고 컨테이너 초기화 중에 Spring이 이를
해결해 줄 것이라고 믿을 수 있습니다.
@Configuration 클래스를 사용할 때는 Java 컴파일러가 설정 모델에 제약을 가하며,
다른 빈에 대한 참조는 유효한 Java 문법이어야 합니다.
다행히도, 이 문제를 해결하는 것은 간단합니다.
이미 논의했듯이,
@Bean 메서드는 빈 의존성을 설명하는 임의 개수의 매개변수를 가질 수 있습니다.
다음 예제와 같이, 여러 @Configuration 클래스가 서로 다른 클래스에 선언된 빈에 의존하는
보다 현실적인 시나리오를 생각해 보겠습니다:
1@Configuration 2public class ServiceConfig { 3 4 @Bean 5 public TransferService transferService(AccountRepository accountRepository) { 6 return new TransferServiceImpl(accountRepository); 7 } 8} 9 10@Configuration 11public class RepositoryConfig { 12 13 @Bean 14 public AccountRepository accountRepository(DataSource dataSource) { 15 return new JdbcAccountRepository(dataSource); 16 } 17} 18 19@Configuration 20@Import({ServiceConfig.class, RepositoryConfig.class}) 21public class SystemTestConfig { 22 23 @Bean 24 public DataSource dataSource() { 25 // return new DataSource 26 } 27} 28 29public static void main(String[] args) { 30 ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class); 31 // everything wires up across configuration classes... 32 TransferService transferService = ctx.getBean(TransferService.class); 33 transferService.transfer(100.00, "A123", "C456"); 34}
1import org.springframework.beans.factory.getBean 2 3@Configuration 4class ServiceConfig { 5 6 @Bean 7 fun transferService(accountRepository: AccountRepository): TransferService { 8 return TransferServiceImpl(accountRepository) 9 } 10} 11 12@Configuration 13class RepositoryConfig { 14 15 @Bean 16 fun accountRepository(dataSource: DataSource): AccountRepository { 17 return JdbcAccountRepository(dataSource) 18 } 19} 20 21@Configuration 22@Import(ServiceConfig::class, RepositoryConfig::class) 23class SystemTestConfig { 24 25 @Bean 26 fun dataSource(): DataSource { 27 // return new DataSource 28 } 29} 30 31fun main() { 32 val ctx = AnnotationConfigApplicationContext(SystemTestConfig::class.java) 33 // everything wires up across configuration classes... 34 val transferService = ctx.getBean<TransferService>() 35 transferService.transfer(100.00, "A123", "C456") 36}
같은 결과를 얻는 다른 방법도 있습니다. @Configuration 클래스는 궁극적으로 컨테이너 내의
또 다른 빈일 뿐이라는 점을 기억하십시오. 이는 다른 빈과 마찬가지로 @Autowired와
@Value 주입 및 기타 기능을 활용할 수 있음을 의미합니다.
이런 방식으로 주입하는 의존성은 가능한 한 가장 단순한 종류여야 합니다.<br>
@Configuration클래스는 컨텍스트 초기화 초기에 상당히 이른 시점에 처리되며,<br>이 방식으로 의존성의 주입을 강제하면 예기치 않게 이른 초기화로<br>이어질 수 있습니다. 가능한 한 앞의 예제와 같이 매개변수 기반 주입을 사용하십시오.<br>동일한 설정 클래스의@PostConstruct메서드 내에서 로컬로 정의된 빈에 대한<br>접근은 피하십시오. 이는 비정적@Bean메서드가 의미상 완전히 초기화된 설정<br>클래스 인스턴스에 대해 호출되어야 하기 때문에 사실상 순환 참조로 이어집니다.<br>순환 참조가 허용되지 않는 경우(예: Spring Boot 2.6+)에는<br>BeanCurrentlyInCreationException이 발생할 수 있습니다.<br>또한@Bean을 통한BeanPostProcessor및BeanFactoryPostProcessor정의에는<br>특히 주의해야 합니다. 이들은 일반적으로static @Bean메서드로 선언되어야 하며,<br>자신을 포함하는 설정 클래스의 인스턴스화를 트리거하지 않아야 합니다. 그렇지 않으면<br>설정 클래스를AutowiredAnnotationBeanPostProcessor보다<br>이른 시점에 빈 인스턴스로 생성할 수 있으므로, 설정 클래스 자체에서<br>@Autowired와@Value가 동작하지 않을 수 있습니다.
다음 예제는 한 빈이 다른 빈에 자동 주입될 수 있는 방법을 보여 줍니다:
1@Configuration 2public class ServiceConfig { 3 4 @Autowired 5 private AccountRepository accountRepository; 6 7 @Bean 8 public TransferService transferService() { 9 return new TransferServiceImpl(accountRepository); 10 } 11} 12 13@Configuration 14public class RepositoryConfig { 15 16 private final DataSource dataSource; 17 18 public RepositoryConfig(DataSource dataSource) { 19 this.dataSource = dataSource; 20 } 21 22 @Bean 23 public AccountRepository accountRepository() { 24 return new JdbcAccountRepository(dataSource); 25 } 26} 27 28@Configuration 29@Import({ServiceConfig.class, RepositoryConfig.class}) 30public class SystemTestConfig { 31 32 @Bean 33 public DataSource dataSource() { 34 // return new DataSource 35 } 36} 37 38public static void main(String[] args) { 39 ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class); 40 // everything wires up across configuration classes... 41 TransferService transferService = ctx.getBean(TransferService.class); 42 transferService.transfer(100.00, "A123", "C456"); 43}
1import org.springframework.beans.factory.getBean 2 3@Configuration 4class ServiceConfig { 5 6 @Autowired 7 lateinit var accountRepository: AccountRepository 8 9 @Bean 10 fun transferService(): TransferService { 11 return TransferServiceImpl(accountRepository) 12 } 13} 14 15@Configuration 16class RepositoryConfig(private val dataSource: DataSource) { 17 18 @Bean 19 fun accountRepository(): AccountRepository { 20 return JdbcAccountRepository(dataSource) 21 } 22} 23 24@Configuration 25@Import(ServiceConfig::class, RepositoryConfig::class) 26class SystemTestConfig { 27 28 @Bean 29 fun dataSource(): DataSource { 30 // return new DataSource 31 } 32} 33 34fun main() { 35 val ctx = AnnotationConfigApplicationContext(SystemTestConfig::class.java) 36 // everything wires up across configuration classes... 37 val transferService = ctx.getBean<TransferService>() 38 transferService.transfer(100.00, "A123", "C456") 39}
대상 빈이 하나의 생성자만 정의하는 경우에는
@Autowired를 지정할 필요가<br>없습니다.
앞의 시나리오에서 @Autowired를 사용하는 것은 잘 동작하며 원하는 모듈성을 제공합니다.
그러나 자동 주입된 빈 정의가 정확히 어디에 선언되어 있는지는 여전히 다소 모호합니다.
예를 들어, ServiceConfig를 보고 있는 개발자로서 @Autowired AccountRepository 빈이
정확히 어디에 선언되어 있는지 어떻게 알 수 있을까요? 코드에 명시적이지 않으며, 이는
전혀 문제가 되지 않을 수도 있습니다.
Spring Tools IDE 지원이
모든 것이 어떻게 연결되어 있는지를 보여 주는 그래프를 렌더링할 수 있는 도구를 제공한다는
점에 유의하십시오. 이는 필요한 모든 것일 수 있습니다. 또한 Java IDE는 AccountRepository
타입의 모든 선언과 사용을 쉽게 찾고 해당 타입을 반환하는 @Bean 메서드의 위치를
빠르게 보여 줄 수 있습니다.
이러한 모호성이 허용되지 않고 IDE 내에서 한 @Configuration 클래스에서 다른
@Configuration 클래스로 직접 탐색하기를 원하는 경우, 설정 클래스 자체를
자동 주입하는 것을 고려하십시오. 다음 예제는 그 방법을 보여 줍니다:
1@Configuration 2public class ServiceConfig { 3 4 @Autowired 5 private RepositoryConfig repositoryConfig; 6 7 @Bean 8 public TransferService transferService() { 9 // navigate 'through' the config class to the @Bean method! 10 return new TransferServiceImpl(repositoryConfig.accountRepository()); 11 } 12}
1@Configuration 2class ServiceConfig { 3 4 @Autowired 5 private lateinit var repositoryConfig: RepositoryConfig 6 7 @Bean 8 fun transferService(): TransferService { 9 // navigate 'through' the config class to the @Bean method! 10 return TransferServiceImpl(repositoryConfig.accountRepository()) 11 } 12}
앞의 상황에서는 AccountRepository가 어디에 정의되어 있는지가 완전히 명시적입니다.
그러나 이제 ServiceConfig는 RepositoryConfig에 강하게 결합되어 있습니다. 이것이
트레이드오프입니다. 이 강한 결합은 인터페이스 기반 또는 추상 클래스 기반의
@Configuration 클래스를 사용함으로써 어느 정도 완화할 수 있습니다.
다음 예제를 살펴보십시오:
1@Configuration 2public class ServiceConfig { 3 4 @Autowired 5 private RepositoryConfig repositoryConfig; 6 7 @Bean 8 public TransferService transferService() { 9 return new TransferServiceImpl(repositoryConfig.accountRepository()); 10 } 11} 12 13@Configuration 14public interface RepositoryConfig { 15 16 @Bean 17 AccountRepository accountRepository(); 18} 19 20@Configuration 21public class DefaultRepositoryConfig implements RepositoryConfig { 22 23 @Bean 24 public AccountRepository accountRepository() { 25 return new JdbcAccountRepository(...); 26 } 27} 28 29@Configuration 30@Import({ServiceConfig.class, DefaultRepositoryConfig.class}) // import the concrete config! 31public class SystemTestConfig { 32 33 @Bean 34 public DataSource dataSource() { 35 // return DataSource 36 } 37 38} 39 40public static void main(String[] args) { 41 ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class); 42 TransferService transferService = ctx.getBean(TransferService.class); 43 transferService.transfer(100.00, "A123", "C456"); 44}
1import org.springframework.beans.factory.getBean 2 3@Configuration 4class ServiceConfig { 5 6 @Autowired 7 private lateinit var repositoryConfig: RepositoryConfig 8 9 @Bean 10 fun transferService(): TransferService { 11 return TransferServiceImpl(repositoryConfig.accountRepository()) 12 } 13} 14 15@Configuration 16interface RepositoryConfig { 17 18 @Bean 19 fun accountRepository(): AccountRepository 20} 21 22@Configuration 23class DefaultRepositoryConfig : RepositoryConfig { 24 25 @Bean 26 fun accountRepository(): AccountRepository { 27 return JdbcAccountRepository(...) 28 } 29} 30 31@Configuration 32@Import(ServiceConfig::class, DefaultRepositoryConfig::class) // import the concrete config! 33class SystemTestConfig { 34 35 @Bean 36 fun dataSource(): DataSource { 37 // return DataSource 38 } 39 40} 41 42fun main() { 43 val ctx = AnnotationConfigApplicationContext(SystemTestConfig::class.java) 44 val transferService = ctx.getBean<TransferService>() 45 transferService.transfer(100.00, "A123", "C456") 46}
이제 ServiceConfig는 구체적인 DefaultRepositoryConfig와 느슨하게 결합되어 있으며,
내장된 IDE 도구도 여전히 유용합니다. RepositoryConfig 구현의 타입 계층을
쉽게 얻을 수 있습니다. 이런 방식으로 @Configuration 클래스와 그 의존성을 탐색하는 것은
인터페이스 기반 코드 탐색의 일반적인 과정과 다르지 않게 됩니다.
@Bean-defined Singletons특정 싱글톤 빈의 시작 생성 순서에 영향을 주고자 한다면, 시작 시가 아니라
첫 접근 시에 생성되도록 일부 빈을 @Lazy로 선언하는 것을 고려하십시오.
@DependsOn은 지정된 빈이 현재 빈보다 먼저 생성되도록 하여, 후자의 직접적인
의존성이 암시하는 것 이상의 다른 빈이 먼저 초기화되도록 강제합니다.
6.2부터 백그라운드 초기화 옵션이 있습니다: @Bean(bootstrap=BACKGROUND)는
컨텍스트 시작 시 각 빈에 대한 전체 빈 생성 단계를 포괄하는 백그라운드 초기화를
위해 특정 빈을 선별할 수 있게 해 줍니다.
논-레이지 주입 지점을 가진 의존 빈은 빈 인스턴스가 완료될 때까지 자동으로
대기합니다. 모든 일반적인 백그라운드 초기화는 컨텍스트 시작 끝에서 완료되도록
강제됩니다. 추가로 @Lazy로 표시된 빈만 나중에(최초 실제 접근 시점까지) 완료되는 것이
허용됩니다.
백그라운드 초기화는 일반적으로 의존 빈의 @Lazy(또는 ObjectProvider)
주입 지점과 함께 사용됩니다. 그렇지 않으면 백그라운드에서 초기화된 빈 인스턴스를
조기에 주입해야 할 때 메인 부트스트랩 스레드가 블록되게 됩니다.
이 형태의 동시 시작은 개별 빈에 적용됩니다. 이러한 빈이 다른 빈에 의존하는
경우, 해당 빈은 이미 초기화되어 있어야 하며, 단순히 먼저 선언되었기 때문이거나
해당 빈에 대한 백그라운드 초기화가 트리거되기 전에 메인 부트스트랩 스레드에서의
초기화를 강제하는 @DependsOn을 통해서일 수 있습니다.
백그라운드 부트스트래핑이 실제로 활성화되려면
Executor타입의bootstrapExecutor빈이<br>선언되어 있어야 합니다. 그렇지 않으면 백그라운드 마커는 런타임에 무시됩니다.<br>부트스트랩 실행기는 시작 용도로만 사용하는 바운디드 실행기일 수도 있고, 다른 목적에도<br>사용되는 공유 스레드 풀일 수도 있습니다.
@Configuration Classes or @Bean Methods임의의 시스템 상태에 따라 전체 @Configuration 클래스나 개별 @Bean 메서드를
조건부로 활성화하거나 비활성화하는 것이 유용한 경우가 자주 있습니다. 이러한 일반적인
예로는 특정 프로파일이 Spring Environment에서 활성화되었을 때만 빈을 활성화하기 위해
@Profile 어노테이션을 사용하는 것입니다(자세한 내용은
Bean Definition Profiles
을 참조하십시오).
@Profile 어노테이션은 실제로 훨씬 더 유연한 어노테이션인
@Conditional을
사용하여 구현됩니다. @Conditional 어노테이션은 @Bean이 등록되기 전에 참조해야 하는
특정 org.springframework.context.annotation.Condition 구현을 나타냅니다.
Condition 인터페이스의 구현은 true 또는 false를 반환하는 matches(…) 메서드를
제공합니다. 예를 들어, 다음 listing은 @Profile에 사용되는 실제 Condition 구현을 보여 줍니다:
1@Override 2public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { 3 // Read the @Profile annotation attributes 4 MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName()); 5 if (attrs != null) { 6 for (Object value : attrs.get("value")) { 7 if (context.getEnvironment().matchesProfiles((String[]) value)) { 8 return true; 9 } 10 } 11 return false; 12 } 13 return true; 14}
1override fun matches(context: ConditionContext, metadata: AnnotatedTypeMetadata): Boolean { 2 // Read the @Profile annotation attributes 3 val attrs = metadata.getAllAnnotationAttributes(Profile::class.java.name) 4 if (attrs != null) { 5 for (value in attrs["value"]!!) { 6 if (context.environment.matchesProfiles(*value as Array<String>)) { 7 return true 8 } 9 } 10 return false 11 } 12 return true 13}
자세한 내용은 @Conditional
javadoc을 참조하십시오.
Spring의 @Configuration 클래스 지원은 Spring XML을 100% 완전히 대체하는 것을 목표로 하지
않습니다. Spring XML 네임스페이스와 같은 일부 기능은 컨테이너를 구성하는 데 있어 여전히
이상적인 방법으로 남아 있습니다.
XML이 편리하거나 필요할 때, 예를 들어
ClassPathXmlApplicationContext를 사용하여 컨테이너를 “XML-centric” 방식으로
인스턴스화하거나 AnnotationConfigApplicationContext와 @ImportResource 어노테이션을
사용하여 필요에 따라 XML을 가져오는 “Java-centric” 방식으로 인스턴스화하는 선택지가
있습니다.
@Configuration ClassesSpring 컨테이너를 XML에서 부트스트랩하고 @Configuration 클래스를 애드혹 방식으로 포함하는
것이 더 바람직할 수 있습니다. 예를 들어 Spring XML을 사용하는 대규모 기존 코드베이스에서는
필요에 따라 @Configuration 클래스를 생성하고 기존 XML 파일에서 이를 포함하는 것이 더 쉽습니다.
이 절의 뒷부분에서는 이러한 종류의 “XML-centric” 상황에서 @Configuration 클래스를 사용하는
옵션을 다룹니다.
@Configuration classes as plain Spring <bean/> elements@Configuration 클래스는 궁극적으로 컨테이너 내의 빈 정의라는 점을 기억하십시오.
이 일련의 예제에서는 AppConfig라는 @Configuration 클래스를 생성하고 이를
system-test-config.xml 내의 <bean/> 정의로 포함합니다.
<context:annotation-config/>가 활성화되어 있기 때문에 컨테이너는 @Configuration
어노테이션을 인식하고 AppConfig에 선언된 @Bean 메서드를 적절히 처리합니다.
다음 예제는 Java와 Kotlin으로 작성된 AppConfig 설정 클래스를 보여 줍니다:
1@Configuration 2public class AppConfig { 3 4 @Autowired 5 private DataSource dataSource; 6 7 @Bean 8 public AccountRepository accountRepository() { 9 return new JdbcAccountRepository(dataSource); 10 } 11 12 @Bean 13 public TransferService transferService() { 14 return new TransferServiceImpl(accountRepository()); 15 } 16}
1@Configuration 2class AppConfig { 3 4 @Autowired 5 private lateinit var dataSource: DataSource 6 7 @Bean 8 fun accountRepository(): AccountRepository { 9 return JdbcAccountRepository(dataSource) 10 } 11 12 @Bean 13 fun transferService() = TransferService(accountRepository()) 14}
다음 예제는 샘플 system-test-config.xml 파일의 일부를 보여 줍니다:
1<beans> 2 <!-- enable processing of annotations such as @Autowired and @Configuration --> 3 <context:annotation-config/> 4 5 <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/> 6 7 <bean class="com.acme.AppConfig"/> 8 9 10 11 <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 12 <property name="url" value="${jdbc.url}"/> 13 <property name="username" value="${jdbc.username}"/> 14 <property name="password" value="${jdbc.password}"/> 15 </bean> 16</beans>
다음 예제는 가능한 jdbc.properties 파일을 보여 줍니다:
1jdbc.url=jdbc:hsqldb:hsql://localhost/xdb 2jdbc.username=sa 3jdbc.password=
1public static void main(String[] args) { 2 ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/com/acme/system-test-config.xml"); 3 TransferService transferService = ctx.getBean(TransferService.class); 4 // ... 5}
1fun main() { 2 val ctx = ClassPathXmlApplicationContext("classpath:/com/acme/system-test-config.xml") 3 val transferService = ctx.getBean<TransferService>() 4 // ... 5}
system-test-config.xml파일에서AppConfig<bean/>은id속성을 선언하지<br>않습니다. 그렇게 해도 무방하지만, 다른 빈이 이를 참조하지 않고, 컨테이너에서 이름으로<br>명시적으로 가져올 가능성이 낮기 때문에 불필요합니다.<br>마찬가지로DataSource빈은 타입에 의해 자동 주입될 뿐이므로 명시적인 빈id가<br>엄밀히 요구되지는 않습니다.
<context:component-scan/> to pick up @Configuration classes@Configuration은 @Component로 메타 어노테이션되어 있기 때문에,
@Configuration으로 어노테이션된 클래스는 자동으로 컴포넌트 스캐닝의 후보가 됩니다.
앞의 예제에서 설명한 것과 동일한 시나리오를 사용하여, 컴포넌트 스캐닝을 활용하도록
system-test-config.xml을 재정의할 수 있습니다. 이 경우 <context:component-scan/>이
동일한 기능을 활성화하므로 <context:annotation-config/>를 명시적으로 선언할 필요가
없다는 점에 유의하십시오.
다음 예제는 수정된 system-test-config.xml 파일을 보여 줍니다:
1<beans> 2 <!-- picks up and registers AppConfig as a bean definition --> 3 <context:component-scan base-package="com.acme"/> 4 5 <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/> 6 7 <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 8 <property name="url" value="${jdbc.url}"/> 9 <property name="username" value="${jdbc.username}"/> 10 <property name="password" value="${jdbc.password}"/> 11 </bean> 12</beans>
@Configuration Class-centric Use of XML with @ImportResource@Configuration 클래스가 컨테이너를 구성하는 기본 메커니즘인 애플리케이션에서도,
적어도 일부 XML을 사용하는 것이 여전히 필요할 수 있습니다. 이러한 시나리오에서는
@ImportResource를 사용하고 필요한 만큼만 XML을 정의할 수 있습니다.
이렇게 하면 컨테이너를 구성하는 “Java-centric” 접근 방식을 구현하면서 XML을 최소한으로 유지할 수 있습니다.
다음 예제(여기에는 설정 클래스, 빈을 정의하는 XML 파일, 프로퍼티 파일, 그리고
main() 메서드가 포함됩니다)는 XML을 필요에 따라 사용하는 “Java-centric” 설정을
실현하기 위해 @ImportResource 어노테이션을 사용하는 방법을 보여 줍니다:
1@Configuration 2@ImportResource("classpath:/com/acme/properties-config.xml") 3public class AppConfig { 4 5 @Value("${jdbc.url}") 6 private String url; 7 8 @Value("${jdbc.username}") 9 private String username; 10 11 @Value("${jdbc.password}") 12 private String password; 13 14 @Bean 15 public DataSource dataSource() { 16 return new DriverManagerDataSource(url, username, password); 17 } 18 19 @Bean 20 public AccountRepository accountRepository(DataSource dataSource) { 21 return new JdbcAccountRepository(dataSource); 22 } 23 24 @Bean 25 public TransferService transferService(AccountRepository accountRepository) { 26 return new TransferServiceImpl(accountRepository); 27 } 28 29}
1@Configuration 2@ImportResource("classpath:/com/acme/properties-config.xml") 3class AppConfig { 4 5 @Value("${jdbc.url}") 6 private lateinit var url: String 7 8 @Value("${jdbc.username}") 9 private lateinit var username: String 10 11 @Value("${jdbc.password}") 12 private lateinit var password: String 13 14 @Bean 15 fun dataSource(): DataSource { 16 return DriverManagerDataSource(url, username, password) 17 } 18 19 @Bean 20 fun accountRepository(dataSource: DataSource): AccountRepository { 21 return JdbcAccountRepository(dataSource) 22 } 23 24 @Bean 25 fun transferService(accountRepository: AccountRepository): TransferService { 26 return TransferServiceImpl(accountRepository) 27 } 28 29}
properties-config.xml
1<beans> 2 <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/> 3</beans>
jdbc.properties
1jdbc.url=jdbc:hsqldb:hsql://localhost/xdb 2jdbc.username=sa 3jdbc.password=
1public static void main(String[] args) { 2 ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); 3 TransferService transferService = ctx.getBean(TransferService.class); 4 // ... 5}
1import org.springframework.beans.factory.getBean 2 3fun main() { 4 val ctx = AnnotationConfigApplicationContext(AppConfig::class.java) 5 val transferService = ctx.getBean<TransferService>() 6 // ... 7}
Using the @Configuration annotation
Programmatic Bean Registration