Home [Spring] 1.12.4. Using the @Configuration annotation
Post
Cancel

[Spring] 1.12.4. Using the @Configuration annotation

1.12.4. Using the @Configuration annotation

@Configuration is a class-level annotation indicating that an object is a source of bean definitions. @Configuration classes declare beans through public @Bean annotated methods. Calls to @Bean methods on @Configuration classes can also be used to define inter-bean dependencies. See Basic Concepts: @Bean and @Configuration for a general introduction.

  • @Configuration은 객체가 bean definitions의 원천(source)임을 나타내는 클래스 수준(class-level)의 annotation이다.
  • @Configuration 클래스는 public @Bean annotated methods을 통해 beans을 선언한다.
  • @Configuration 클래스의 @Bean methods에 대한 호출을 사용하여 빈 간 종속성(inter-bean dependencies)을 정의할 수도 있다.
  • 일반 소개는 기본 개념: Basic Concepts: @Bean and @Configuration을 참조하십시오.

Injecting Inter-bean Dependencies

When beans have dependencies on one another, expressing that dependency is as simple as having one bean method call another, as the following example shows:

  • bean들이 서로 의존하고 있을 때, 그 의존성을 표현하는 것은 다음 예에서 알 수 있듯이 하나의 bean method가 다른 bean method를 부르는 것처럼 간단하다.
1
2
3
4
5
6
7
8
9
@Configuration
class AppConfig {

    @Bean
    fun beanOne() = BeanOne(beanTwo())

    @Bean
    fun beanTwo() = BeanTwo()
}

In the preceding example, beanOne receives a reference to beanTwo through constructor injection.

  • 앞의 예에서 beanOne은 생성자 주입(constructor injection)을 통해 beanTwo에 대한 참조를 받는다.

This method of declaring inter-bean dependencies works only when the @Bean method is declared within a @Configuration class. You cannot declare inter-bean dependencies by using plain @Component classes.

  • 빈 간 종속성(inter-bean dependencies)을 선언하는 이 방법은 @Bean 방법이 @Configuration 클래스 내에서 선언될 때만 효과가 있다.
  • 일반 @Component 클래스를 사용하여 빈 간 종속성(inter-bean dependencies)을 선언할 수 없다. ..

Lookup Method Injection

As noted earlier, lookup method injection is an advanced feature that you should use rarely. It is useful in cases where a singleton-scoped bean has a dependency on a prototype-scoped bean. Using Java for this type of configuration provides a natural means for implementing this pattern. The following example shows how to use lookup method injection:

  • 앞에서 설명한 것처럼 lookup method injection은 거의 사용하지 않는 고급 기능이다.
  • singleton-scoped bean이 prototype-scoped bean에 의존하는 경우에 유용하다.
  • 이러한 유형의 구성에 자바를 사용하는 것은 이 패턴을 구현하기 위한 자연스러운 수단을 제공한다.
  • 다음 예제는 lookup method injection 사용 방법을 보여준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
abstract class CommandManager {
    fun process(commandState: Any): Any {
        // grab a new instance of the appropriate Command interface
        val command = createCommand()
        // set the state on the (hopefully brand new) Command instance
        command.setState(commandState)
        return command.execute()
    }

    // okay... but where is the implementation of this method?
    protected abstract fun createCommand(): Command
		fun test(): String {

		}
}

By using Java configuration, you can create a subclass of CommandManager where the abstract createCommand() method is overridden in such a way that it looks up a new (prototype) command object. The following example shows how to do so:

  • Java configuration을 사용하여 추상 createCommand() 메서드가 새로운 (프로토타입) command object를 조회하는 방식으로 재정의되는 CommandManager의 하위 클래스를 만들 수 있다.
  • 다음 예제는 이를 수행하는 방법을 보여준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Bean
@Scope("prototype")
fun asyncCommand(): AsyncCommand {
    val command = AsyncCommand()
    // inject dependencies here as required
    return command
}

@Bean
fun commandManager(): CommandManager {
    // return new anonymous implementation of CommandManager with createCommand()
    // overridden to return a new prototype Command object
    return object : CommandManager() {
        override fun createCommand(): Command {
            return asyncCommand()
        }
    }
}

Further Information About How Java-based Configuration Works Internally

Consider the following example, which shows a @Bean annotated method being called twice:

  • @Bean annotated method가 두 번 호출되는 것을 보여주는 다음 예를 생각해 보십시오.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Configuration
class AppConfig {

    @Bean
    fun clientService1(): ClientService {
        return ClientServiceImpl().apply {
            clientDao = clientDao()
        }
    }

    @Bean
    fun clientService2(): ClientService {
        return ClientServiceImpl().apply {
            clientDao = clientDao()
        }
    }

    @Bean
    fun clientDao(): ClientDao {
        return ClientDaoImpl()
    }
}

clientDao() has been called once in clientService1() and once in clientService2(). Since this method creates a new instance of ClientDaoImpl and returns it, you would normally expect to have two instances (one for each service). That definitely would be problematic: In Spring, instantiated beans have a singleton scope by default. This is where the magic comes in: All @Configuration classes are subclassed at startup-time with CGLIB. In the subclass, the child method checks the container first for any cached (scoped) beans before it calls the parent method and creates a new instance.

  • clientDao()clientService1()에서 한 번, clientService2()에서 한 번 호출되었다.
  • 이 방법은 ClientDaoImpl의 새 인스턴스를 생성하고 반환하므로 일반적으로 두 개의 인스턴스(각 서비스마다 하나씩)가 있을 것으로 예상한다.
  • 그것은 분명히 문제가 될 것이다: Spring에 instantiated beans는 기본적으로 singleton 범위를 가진다.
  • 여기에서 마법이 등장함: 모든 @Configuration 클래스는 시작 시 CGLIB로 하위 분류된다.
  • 하위 클래스에서 하위 메서드는 먼저 container에서 캐시된(스코프된) beans을 확인한 후 상위 메서드를 호출하고 새 인스턴스를 생성한다.

The behavior could be different according to the scope of your bean. We are talking about singletons here.

  • bean의 범위에 따라 행동이 달라질 수 있다.
  • 우리는 여기서 singletons에 대해 이야기하고 있다.

As of Spring 3.2, it is no longer necessary to add CGLIB to your classpath because CGLIB classes have been repackaged under org.springframework.cglib and included directly within the spring-core JAR.

  • Spring 3.2를 기준으로 CGLIB 클래스는 org.springframework.cglib로 재포장되어 스프링 코어 JAR에 직접 포함되었기 때문에 더 이상 클래스 경로에 CGLIB를 추가할 필요가 없다.

There are a few restrictions due to the fact that CGLIB dynamically adds features at startup-time. In particular, configuration classes must not be final. However, as of 4.3, any constructors are allowed on configuration classes, including the use of @Autowired or a single non-default constructor declaration for default injection.

If you prefer to avoid any CGLIB-imposed limitations, consider declaring your @Bean methods on non- @Configuration classes (for example, on plain @Component classes instead). Cross-method calls between @Bean methods are not then intercepted, so you have to exclusively rely on dependency injection at the constructor or method level there.

  • 시작 시 CGLIB가 기능을 동적으로 추가한다는 점 때문에 몇 가지 제약이 있다.
  • 특히 configuration classes가 final이면 안 된다.
  • 단, 4.3을 기준으로 @Autorward 또는 single non-default constructor declaration을 default injection에 사용하는 것을 포함하여 모든 생성자가 configuration classes에 허용된다.

  • CGLIB가 부과한(CGLIB-imposed) 제한을 피하려면 @Configuration 클래스가 아닌 다른 클래스(예: 일반 @Component 클래스 대신)에서 @Bean methods를 선언해 보십시오.
  • @Bean 방법 사이의 Cross-method calls은 그 다음에 가로채지 않기 때문에, 그곳의 생성자 또는 method 수준에서 의존성 주입에만 전적으로 의존해야 한다.

References

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

[Spring] 1.12.3. Using the @Bean Annotation

[Spring] 1.12.5. Composing Java-based Configurations