Home [Spring] 1.12.5. Composing Java-based Configurations
Post
Cancel

[Spring] 1.12.5. Composing Java-based Configurations

1.12.5. Composing Java-based Configurations

Spring’s Java-based configuration feature lets you compose annotations, which can reduce the complexity of your configuration.

  • 스프링의 Java-based configuration 기능을 사용하면 annotations을 작성할 수 있어 configuration의 복잡성을 줄일 수 있다.

Using the @Import Annotation

Much as the <import/> element is used within Spring XML files to aid in modularizing configurations, the @Import annotation allows for loading @Bean definitions from another configuration class, as the following example shows:

  • configurations 모듈화를 지원하기 위해 스프링 XML 파일 내에서 <import/> 요소를 사용하는 경우가 많으므로, @Import annotation은 다음 예시처럼 다른 구성 클래스에서 @Bean 정의를 로드할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration
class ConfigA {

    @Bean
    fun a(): A = A()
}

@Configuration
**@Import(ConfigA::class)**
class ConfigB {

    @Bean
    fun b(): B = B()
}

Now, rather than needing to specify both ConfigA.class and ConfigB.class when instantiating the context, only ConfigB needs to be supplied explicitly, as the following example shows:

  • 이제 컨텍스트를 인스턴스화할 때 ConfigA.classConfigB.class를 모두 지정할 필요 없이, 다음 예시처럼 ConfigB만 명시적으로 공급하면 된다.
1
2
3
4
5
6
7
8
9
import org.springframework.beans.factory.getBean

fun main() {
    val ctx = AnnotationConfigApplicationContext(ConfigB::class.java)

    // now both beans A and B will be available...
    val a = ctx.getBean<A>()
    val b = ctx.getBean<B>()
}

This approach simplifies container instantiation, as only one class needs to be dealt with, rather than requiring you to remember a potentially large number of @Configuration classes during construction.

  • 이 접근방식은 construction 중 잠재적으로 많은 수의 @Configuration 클래스를 기억하도록 요구하지 않고 하나의 클래스만 처리해야 하므로 컨테이너 인스턴스화를 단순화한다.

As of Spring Framework 4.2, @Import also supports references to regular component classes, analogous to the AnnotationConfigApplicationContext.register method. This is particularly useful if you want to avoid component scanning, by using a few configuration classes as entry points to explicitly define all your components.

  • Spring Framework 4.2를 기준으로 @ImportAnnotationConfigApplicationContext.register 방법과 유사한 일반 component 클래스에 대한 참조(references)도 지원한다.
  • 이것은 특히 몇 개의 configuration 클래스를 입력 지점으로 사용하여 모든 components를 명시적으로 정의함으로써 component scanning을 방지하려는 경우에 유용하다.

Injecting Dependencies on Imported @Bean Definitions

The preceding example works but is simplistic. In most practical scenarios, beans have dependencies on one another across configuration classes. When using XML, this is not an issue, because no compiler is involved, and you can declare ref="someBean" and trust Spring to work it out during container initialization. When using @Configuration classes, the Java compiler places constraints on the configuration model, in that references to other beans must be valid Java syntax.

  • 앞의 예는 효과가 있지만 단순하다.
  • 대부분의 실제 시나리오에서 beans은 configuration 클래스에 걸쳐 서로 의존한다.
  • XML을 사용할 때는 컴파일러가 관련되지 않으며 ref="someBean"을 선언하고 Spring을 신뢰하여 컨테이너 초기화 중에 문제를 해결할 수 있다.
  • @Configuration 클래스를 사용할 때, Java 컴파일러는 configuration 모델에 제약을 가하며, 다른 beans에 대한 참조는 유효한 Java 구문이어야 한다.

Fortunately, solving this problem is simple. As we already discussed, a @Bean method can have an arbitrary number of parameters that describe the bean dependencies. Consider the following more real-world scenario with several @Configuration classes, each depending on beans declared in the others:

  • 다행히 이 문제를 해결하는 것은 간단하다.
  • 이미 논의한 바와 같이 @Bean 방법은 bean dependencies을 기술하는 임의의 수의 파라미터를 가질 수 있다.
  • 각 클래스는 다른 클래스에 선언된 beans에 따라 @Configuration 클래스가 여러 개인 다음과 같은 실제 시나리오를 고려해 보십시오.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import org.springframework.beans.factory.getBean

@Configuration
class ServiceConfig {

    @Bean
    fun transferService(accountRepository: AccountRepository): TransferService {
        return TransferServiceImpl(accountRepository)
    }
}

@Configuration
class RepositoryConfig {

    @Bean
    fun accountRepository(dataSource: DataSource): AccountRepository {
        return JdbcAccountRepository(dataSource)
    }
}

@Configuration
@Import(ServiceConfig::class, RepositoryConfig::class)
class SystemTestConfig {

    @Bean
    fun dataSource(): DataSource {
        // return new DataSource
    }
}

@Configuration
@Import(ServiceConfig::class, RepositoryConfig::class)
class SystemProdConfig {

    @Bean
    fun dataSource(): DataSource {
        // return new DataSource
    }
}

fun main() {
    val ctx = AnnotationConfigApplicationContext(SystemTestConfig::class.java)
    // everything wires up across configuration classes...
    val transferService = ctx.getBean<TransferService>()
    transferService.transfer(100.00, "A123", "C456")
}

There is another way to achieve the same result. Remember that @Configuration classes are ultimately only another bean in the container: This means that they can take advantage of @Autowired and @Value injection and other features the same as any other bean.

  • 같은 결과를 얻을 수 있는 다른 방법이 있다.
  • @Configuration 클래스는 궁극적으로 컨테이너의 또 다른 bean일 뿐이라는 점을 기억하자.
  • 이것은 그들이 @Autored@Value injection 및 다른 특징들을 다른 어떤 bean과 동일하게 이용할 수 있다는 것을 의미한다.

Make sure that the dependencies you inject that way are of the simplest kind only. @Configuration classes are processed quite early during the initialization of the context, and forcing a dependency to be injected this way may lead to unexpected early initialization. Whenever possible, resort to parameter-based injection, as in the preceding example.

Also, be particularly careful with BeanPostProcessor and BeanFactoryPostProcessor definitions through @Bean. Those should usually be declared as static @Bean methods, not triggering the instantiation of their containing configuration class. Otherwise, @Autowired and @Value may not work on the configuration class itself, since it is possible to create it as a bean instance earlier than AutowiredAnnotationBeanPostProcessor.

  • 이러한 방식으로 주입하는 종속성(dependencies)이 가장 단순한 종류인지 확인하자.
  • @Configuration 클래스는 컨텍스트 초기화 중에 상당히 일찍 처리되며, 이러한 방식으로 종속성을 주입하도록 강제하면 예기치 않은 초기화를 초래할 수 있다.
  • 가능하면 앞의 예와 같이 parameter-based injection을 사용하자.

  • 또한 @Bean을 통해 BeanPostProcessorBeanFactoryPostProcessor 정의를 특히 주의하자.
  • 이러한 방법은 일반적으로 static @Bean 방법으로 선언해야 하며, 포함된 configuration 클래스의 인스턴스화를 유발하지 않아야 한다.
  • 그렇지 않으면 AutoboredAnnotationBeanPostProcessor보다 먼저 bean instance로 생성할 수 있으므로 @Autowired@Value가 configuration 클래스 자체에서 작동하지 않을 수 있다.

The following example shows how one bean can be autowired to another bean:

  • 다음 예는 한 bean을 다른 bean에 autowired하는 방법을 보여준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import org.springframework.beans.factory.getBean

@Configuration
class ServiceConfig {

    @Autowired
    lateinit var accountRepository: AccountRepository

    @Bean
    fun transferService(): TransferService {
        return TransferServiceImpl(accountRepository)
    }
}

@Configuration
class RepositoryConfig(private val dataSource: DataSource) {

    @Bean
    fun accountRepository(): AccountRepository {
        return JdbcAccountRepository(dataSource)
    }
}

@Configuration
@Import(ServiceConfig::class, RepositoryConfig::class)
class SystemTestConfig {

    @Bean
    fun dataSource(): DataSource {
        // return new DataSource
    }
}

fun main() {
    val ctx = AnnotationConfigApplicationContext(SystemTestConfig::class.java)
    // everything wires up across configuration classes...
    val transferService = ctx.getBean<TransferService>()
    transferService.transfer(100.00, "A123", "C456")
}

Constructor injection in @Configuration classes is only supported as of Spring Framework 4.3. Note also that there is no need to specify @Autowired if the target bean defines only one constructor.

  • @Configuration 클래스의 생성자 주입은 Spring Framework 4.3을 기준으로만 지원된다.
  • 또한 target bean이 하나의 생성자만 정의하는 경우 @Autowired를 지정할 필요가 없다는 점에 유의하자.

Fully-qualifying imported beans for ease of navigation

In the preceding scenario, using @Autowired works well and provides the desired modularity, but determining exactly where the autowired bean definitions are declared is still somewhat ambiguous. For example, as a developer looking at ServiceConfig, how do you know exactly where the @Autowired AccountRepository bean is declared? It is not explicit in the code, and this may be just fine. Remember that the Spring Tools for Eclipse provides tooling that can render graphs showing how everything is wired, which may be all you need. Also, your Java IDE can easily find all declarations and uses of the AccountRepository type and quickly show you the location of @Bean methods that return that type.

  • 앞의 시나리오에서, @Autowired를 사용하는 것은 잘 작동하고 원하는 모듈화를 제공하지만, autowired bean definitions가 선언되는 정확한 위치를 결정하는 것은 여전히 다소 모호하다.
  • 예를 들어, ServiceConfig를 살펴본 개발자로서 @Autorated AccountRepository bean이 선언된 위치를 정확히 어떻게 알 수 있는가?
  • 그것은 코드에 명시되어 있지 않지만, 사실 그냥 괜찮다.
  • Spring Tools for Eclipse는 당신이 필요로 하는 전부일 수있는 모든 것이 어떻게 wired되어 있는지 보여주는 그래프를 렌더링할 수 있는 도구를 제공한다는 것을 기억하자.
  • 또한, 당신의 Java IDE는 AccountRepository type의 모든 declarations과 uses을 쉽게 찾을 수 있고, 그 type을 반환하는 @Bean methods의 위치를 빠르게 보여줄 수 있다.

In cases where this ambiguity is not acceptable and you wish to have direct navigation from within your IDE from one @Configuration class to another, consider autowiring the configuration classes themselves. The following example shows how to do so:

  • 이러한 모호성이 허용되지 않고 IDE 내에서 @Configuration 클래스 간에 직접 탐색하려는 경우 configuration classes 자체를 autowiring 하는 것을 고려하자.
  • 다음 예제는 이를 수행하는 방법을 보여준다.
1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
class ServiceConfig {

    @Autowired
    private lateinit var repositoryConfig: RepositoryConfig

    @Bean
    fun transferService(): TransferService {
        // navigate 'through' the config class to the @Bean method!
        return TransferServiceImpl(repositoryConfig.accountRepository())
    }
}

In the preceding situation, where AccountRepository is defined is completely explicit. However, ServiceConfig is now tightly coupled to RepositoryConfig. That is the tradeoff. This tight coupling can be somewhat mitigated by using interface-based or abstract class-based @Configuration classes. Consider the following example:

  • 앞의 상황에서 AccountRepository가 정의된 곳은 완전히 명백하다.
  • 그러나 ServiceConfig는 이제 RepositoryConfig와 긴밀하게 연결된다.
  • 그것이 절충(tradeoff)이다.
  • 이러한 긴밀한 결합은 인터페이스 기반(interface-based) 또는 추상 클래스 기반(abstract class-based) @Configuration 클래스를 사용함으로써 다소 완화할 수 있다.
  • 다음 예를 고려해 보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import org.springframework.beans.factory.getBean

@Configuration
class ServiceConfig {

    @Autowired
    private lateinit var repositoryConfig: RepositoryConfig

    @Bean
    fun transferService(): TransferService {
        return TransferServiceImpl(repositoryConfig.accountRepository())
    }
}

@Configuration
interface RepositoryConfig {

    @Bean
    fun accountRepository(): AccountRepository
}

@Configuration
class DefaultRepositoryConfig : RepositoryConfig {

    @Bean
    fun accountRepository(): AccountRepository {
        return JdbcAccountRepository(...)
    }
}

@Configuration
@Import(ServiceConfig::class, DefaultRepositoryConfig::class)  // import the concrete config!
class SystemTestConfig {

    @Bean
    fun dataSource(): DataSource {
        // return DataSource
    }

}

fun main() {
    val ctx = AnnotationConfigApplicationContext(SystemTestConfig::class.java)
    val transferService = ctx.getBean<TransferService>()
    transferService.transfer(100.00, "A123", "C456")
}

Now ServiceConfig is loosely coupled with respect to the concrete DefaultRepositoryConfig, and built-in IDE tooling is still useful: You can easily get a type hierarchy of RepositoryConfig implementations. In this way, navigating @Configuration classes and their dependencies becomes no different than the usual process of navigating interface-based code.

  • 이제 ServiceConfig는 구체적인 DefaultRepositoryConfig와 느슨하게 결합되어 있으며, 내장된 IDE tooling은 여전히 유용하다.
  • 우리는 RepositoryConfig 구현의 유형 계층 구조를 쉽게 얻을 수 있다.
  • 이와 같이 @Configuration 클래스 및 그 종속성을 탐색하는 것은 인터페이스 기반(interface-based) 코드를 탐색하는 일반적인 프로세스와 다르지 않게 된다.

If you want to influence the startup creation order of certain beans, consider declaring some of them as @Lazy (for creation on first access instead of on startup) or as @DependsOn certain other beans (making sure that specific other beans are created before the current bean, beyond what the latter’s direct dependencies imply).

  • 특정 beans의 시작 생성 순서에 영향을 미치려면 일부 bean을 @Lazy(시작 대신 처음 액세스 시 생성) 또는 @DependsOn(특정 다른 beans이 현재 bean보다 먼저 생성되도록 함)으로 선언하는 것을 고려하자.

Conditionally Include @Configuration Classes or @Bean Methods

It is often useful to conditionally enable or disable a complete @Configuration class or even individual @Bean methods, based on some arbitrary system state. One common example of this is to use the @Profile annotation to activate beans only when a specific profile has been enabled in the Spring Environment (see Bean Definition Profiles for details).

  • 어떤 임의의 시스템 상태에 기초하여 완전한 @Configuration 클래스 또는 심지어 개별 @Bean 메소드를 조건부로 활성화하거나 비활성화하는 것이 종종 유용하다.
  • 이에 대한 일반적인 예로는 스프링 Environment에서 특정 프로필을 활성화한 경우에만 @Profile 주석을 사용하여 beans을 활성화하는 것이다
  • (자세한 내용은 Bean Definition Profiles 참조).

The @Profile annotation is actually implemented by using a much more flexible annotation called @Conditional. The @Conditional annotation indicates specific org.springframework.context.annotation.Condition implementations that should be consulted before a @Bean is registered.

  • @Profile annotation은 실제로 @Conditional이라는 훨씬 유연한 annotation을 사용하여 구현된다.
  • @Conditional annotation은 @Bean을 등록하기 전에 참조해야 하는 특정 org.springframework.context.notation.Condition을 나타낸다.

Implementations of the Condition interface provide a matches(…) method that returns true or false. For example, the following listing shows the actual Condition implementation used for @Profile:

  • Condition 인터페이스의 구현은 true 또는 false을 반환하는 matches(…) method를 제공한다.
  • 예를 들어, 다음 목록은 @Profile에 사용된 실제 Condition 구현을 보여준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
override fun matches(context: ConditionContext, metadata: AnnotatedTypeMetadata): Boolean {
    // Read the @Profile annotation attributes
    val attrs = metadata.getAllAnnotationAttributes(Profile::class.java.name)
    if (attrs != null) {
        for (value in attrs["value"]!!) {
            if (context.environment.acceptsProfiles(Profiles .of(*value as Array<String>))) {
                return true
            }
        }
        return false
    }
    return true
}

See the @Conditional javadoc for more detail.

Combining Java and XML Configuration

Spring’s @Configuration class support does not aim to be a 100% complete replacement for Spring XML. Some facilities, such as Spring XML namespaces, remain an ideal way to configure the container. In cases where XML is convenient or necessary, you have a choice: either instantiate the container in an “XML-centric” way by using, for example, ClassPathXmlApplicationContext, or instantiate it in a “Java-centric” way by using AnnotationConfigApplicationContext and the @ImportResource annotation to import XML as needed.

  • 스프링의 @Configuration 클래스 지원은 스프링 XML을 100% 완전 교체하는 것을 목표로 하지 않는다.
  • 스프링 XML 네임스페이스와 같은 일부 facilities는 컨테이너를 구성하는 이상적인 방법으로 남아 있다.
  • XML이 편리하거나 필요한 경우, 우리는 선택할 수 있다:
  • 예를 들어 ClassPathXmlApplicationContext를 사용하여 컨테이너를 “XML-centric” 방식으로 인스턴스화하거나, AnnotationConfigApplicationContext@ImportResource annotation을 사용하여 필요에 따라 XML을 가져오는 “Java-centric” 방식으로 인스턴스화하는 방법을 선택할 수 있다.

XML-centric Use of @Configuration Classes

It may be preferable to bootstrap the Spring container from XML and include @Configuration classes in an ad-hoc fashion. For example, in a large existing codebase that uses Spring XML, it is easier to create @Configuration classes on an as-needed basis and include them from the existing XML files. Later in this section, we cover the options for using @Configuration classes in this kind of “XML-centric” situation.

  • XML에서 스프링 컨테이너를 부트스트랩하는 것이 더 바람직할 수 있으며 @Configuration 클래스를 ad-hoc 방식으로 포함할 수 있다.
  • 예를 들어 스프링 XML을 사용하는 대형 기존 codebase에서는 필요 시 @Configuration 클래스를 생성하여 기존 XML 파일에서 포함시키는 것이 더 쉽다.
  • 이 섹션 후반부에서는 이러한 종류의 “XML-centric” 상황에서 @Configuration 클래스를 사용하는 옵션에 대해 다룹니다.

Declaring @Configuration classes as plain Spring <bean/> elements

Remember that @Configuration classes are ultimately bean definitions in the container. In this series examples, we create a @Configuration class named AppConfig and include it within system-test-config.xml as a <bean/> definition. Because <context:annotation-config/> is switched on, the container recognizes the @Configuration annotation and processes the @Bean methods declared in AppConfig properly.

The following example shows an ordinary configuration class in Java:

  • @Configuration 클래스는 궁극적으로 container의 bean definitions라는 점을 기억하자.
  • 이 시리즈 예에서는 AppConfig라는 @Configuration 클래스를 생성하여 system-test-config.xml<bean/> 정의로 포함시킨다.
  • <context:annotation-config/>가 켜져 있기 때문에 컨테이너는 @Configuration annotation을 인식하고 AppConfig에 선언된 @Bean 메서드를 적절하게 처리한다.
  • 다음 예제는 Java의 일반 구성 클래스를 보여준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration
class AppConfig {

    @Autowired
    private lateinit var dataSource: DataSource

    @Bean
    fun accountRepository(): AccountRepository {
        return JdbcAccountRepository(dataSource)
    }

    @Bean
    fun transferService() = TransferService(accountRepository())
}

The following example shows part of a sample system-test-config.xml file:

1
2
3
4
5
6
7
8
9
10
11
12
13
<beans>
    <!-- enable processing of annotations such as @Autowired and @Configuration -->
    <context:annotation-config/>
    <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>

    <bean class="com.acme.AppConfig"/>

    <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
</beans>

The following example shows a possible jdbc.properties file:

1
2
3
jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
jdbc.username=sa
jdbc.password=
1
2
3
4
5
fun main() {
    val ctx = ClassPathXmlApplicationContext("classpath:/com/acme/system-test-config.xml")
    val transferService = ctx.getBean<TransferService>()
    // ...
}

In system-test-config.xml file, the AppConfig <bean/> does not declare an id element. While it would be acceptable to do so, it is unnecessary, given that no other bean ever refers to it, and it is unlikely to be explicitly fetched from the container by name. Similarly, the DataSource bean is only ever autowired by type, so an explicit bean id is not strictly required.

  • system-test-config.xml 파일에서 AppConfig <bean/>id 요소를 선언하지 않는다.
  • 그렇게 하는 것은 용인될 수 있겠지만, 다른 bean이 전혀 언급되지 않고, 이름만으로 container에서 명시적으로 꺼낼 것 같지 않다는 점에서 불필요하다.
  • 마찬가지로 DataSource bean은 유형별로만 autowired되기 때문에 명시적인 bean id가 엄격히 요구되지는 않는다.

Using to pick up @Configuration classes

Because @Configuration is meta-annotated with @Component, @Configuration-annotated classes are automatically candidates for component scanning. Using the same scenario as describe in the previous example, we can redefine system-test-config.xml to take advantage of component-scanning. Note that, in this case, we need not explicitly declare <context:annotation-config/>, because <context:component-scan/> enables the same functionality.

The following example shows the modified system-test-config.xml file:

  • @Configuration@Component와 함께 meta-annotated되기 때문에 @Configuration-annotated 클래스는 자동으로 component scanning 검색 대상이다.
  • 앞의 예에서 설명한 것과 동일한 시나리오를 사용하여, component-scanning을 활용하기 위해 system-test-config.xml을 재정의할 수 있다.
  • 이 경우에는 <context:component-scan/>이 동일한 기능을 가능하게 하기 때문에 <context:annotation-config/>를 명시적으로 선언할 필요가 없다는 점에 유의한다.
  • 다음 예제는 수정된 system-test-config.xml 파일을 보여준다.
1
2
3
4
5
6
7
8
9
10
11
<beans>
    <!-- picks up and registers AppConfig as a bean definition -->
    <context:component-scan base-package="com.acme"/>
    <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>

    <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
</beans>

@Configuration Class-centric Use of XML with @ImportResource

In applications where @Configuration classes are the primary mechanism for configuring the container, it is still likely necessary to use at least some XML. In these scenarios, you can use @ImportResource and define only as much XML as you need. Doing so achieves a “Java-centric” approach to configuring the container and keeps XML to a bare minimum. The following example (which includes a configuration class, an XML file that defines a bean, a properties file, and the main class) shows how to use the @ImportResource annotation to achieve “Java-centric” configuration that uses XML as needed:

  • @Configuration 클래스가 컨테이너를 구성하는 기본 메커니즘인 애플리케이션에서는 여전히 일부 XML을 사용해야 할 가능성이 높다.
  • 이러한 시나리오에서는 @ImportResource를 사용하고 필요한 만큼의 XML만 정의할 수 있다.
  • 그렇게 하면 컨테이너 구성에 대한 “Java-centric” 접근방식이 달성되고 XML을 최소로 유지할 수 있다.
  • 다음 예(configuration class, bean, properties file 및 main class를 정의하는 XML 파일 포함)는 @ImportResource annotation을 사용하여 필요에 따라 XML을 사용하는 “Java-centric” configuration을 달성하는 방법을 보여준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Configuration
@ImportResource("classpath:/com/acme/properties-config.xml")
class AppConfig {

    @Value("\${jdbc.url}")
    private lateinit var url: String

    @Value("\${jdbc.username}")
    private lateinit var username: String

    @Value("\${jdbc.password}")
    private lateinit var password: String

    @Bean
    fun dataSource(): DataSource {
        return DriverManagerDataSource(url, username, password)
    }
}
1
2
3
4
properties-config.xml
<beans>
    <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
</beans>
1
2
3
4
jdbc.properties
jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
jdbc.username=sa
jdbc.password=
1
2
3
4
5
6
7
import org.springframework.beans.factory.getBean

fun main() {
    val ctx = AnnotationConfigApplicationContext(AppConfig::class.java)
    val transferService = ctx.getBean<TransferService>()
    // ...
}

References

This post is licensed under CC BY 4.0 by the author.

[Spring] 1.12.4. Using the @Configuration annotation

[Spring] 1.13. Environment Abstraction