@Bean Lite Mode & inter-bean references

@Bean Methods in @Configuration Classes

일반적으로 @Bean 어노테이션은 @Configuration 어노테이션이 사용된 클래스 내의 메서드에 선언이 됩니다. 이 경우 @Bean 어노테이션을 사용하는 메서드는 같은 클래스의 다른 @Bean 메소드를 직접 호출하여 참조할 수 있습니다. 이렇게하면 bean 간의 참조(reference)가 강하게 만들어집니다.

아래 코드의 실행 후 로그를 통해 a() 메서드의 결과로 생성되는 A 클래스의 빈은 b() 와 c() 메서드에서 a() 메서드를 직접 호출해 참조가 되는 것을 확인할 수 있습니다.

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
47
48
49
50
51
52
53
54
55
56
57
@SpringBootApplication
public class TestApplication {

@Autowired
private ApplicationContext context;

public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(TestApplication.class, args);
}

@Configuration
public static class TestConfiguration {

@Bean
public A a() {
return new A();
}

@Bean
public B b() {
A a = a();
System.out.println(a);
return new B();
}

@Bean
public C c() {
A a = a();
System.out.println(a);
return new C();
}
}

public static class A {
}

public static class B {
}

public static class C {
}
}


// 샐행 결과
2019-04-30 19:41:04.837 INFO 24509 --- [ main] com.example.test.TestApplication : Starting TestApplication on AL01297960.local with PID 24509 (/Users/user/work/test/build/classes/java/main started by user in /Users/user/work/test)
2019-04-30 19:41:04.841 INFO 24509 --- [ main] com.example.test.TestApplication : No active profile set, falling back to default profiles: default
2019-04-30 19:41:06.229 INFO 24509 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2019-04-30 19:41:06.262 INFO 24509 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-04-30 19:41:06.262 INFO 24509 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.17]
2019-04-30 19:41:06.353 INFO 24509 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-04-30 19:41:06.353 INFO 24509 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1441 ms
com.example.test.TestApplication$A@42163c37
com.example.test.TestApplication$A@42163c37
2019-04-30 19:41:06.620 INFO 24509 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-04-30 19:41:06.846 INFO 24509 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-04-30 19:41:06.850 INFO 24509 --- [ main] com.example.test.TestApplication : Started TestApplication in 2.489 seconds (JVM running for 3.45)

이러한 관계를 **빈 간의 참조(inter-bean references)**라 부릅니다. 이러한 빈 간의 참조는 @Configuration 클래스의 @Bean이 cglib wrapper에 의해 래핑되기 때문에 동작하게 됩니다.(@Bean 메서드에 대한 호출을 가로채고 Bean 인스턴스를 컨텍스트에서 반환하게 됩니다.)

@Bean Lite Mode

처음 알게된 분도 계실 수 있을텐데요, @Bean 메소드는 @Configuration으로 주석을 달지 않은 클래스 내에서도 선언 될 수도 있습니다. 이런 경우, @Bean 메서드는 **lite mode**로 처리됩니다.

lite mode의 Bean 메서드는 스프링 컨테이너에 의해 일반 팩토리 메서드로 처리됩니다. 그렇기 때문에, lite mode에서는 빈 간의 참조가 지원되지 않습니다.

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
47
48
49
50
51
52
53
54
55
56
57
@SpringBootApplication
public class TestApplication {

@Autowired
private ApplicationContext context;

public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(TestApplication.class, args);
}

@Configuration
public static class TestConfiguration {

public A a() {
return new A();
}

@Bean
public B b() {
A a = a();
System.out.println(a);
return new B();
}

@Bean
public C c() {
A a = a();
System.out.println(a);
return new C();
}
}

public static class A {
}

public static class B {
}

public static class C {
}
}


// 실행 결과
```java
2019-04-30 20:02:17.530 INFO 65524 --- [ main] com.example.test.TestApplication : Starting TestApplication on AL01297960.local with PID 65524 (/Users/user/work/test/build/classes/java/main started by user in /Users/user/work/test)
2019-04-30 20:02:17.534 INFO 65524 --- [ main] com.example.test.TestApplication : No active profile set, falling back to default profiles: default
2019-04-30 20:02:18.857 INFO 65524 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2019-04-30 20:02:18.891 INFO 65524 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-04-30 20:02:18.891 INFO 65524 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.17]
2019-04-30 20:02:18.973 INFO 65524 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-04-30 20:02:18.973 INFO 65524 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1368 ms
com.example.test.TestApplication$A@919d542c
com.example.test.TestApplication$A@414fc49c
2019-04-30 20:02:19.240 INFO 65524 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-04-30 20:02:19.471 INFO 65524 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-04-30 20:02:19.474 INFO 65524 --- [ main] com.example.test.TestApplication : Started TestApplication in 2.406 seconds (JVM running for 3.2)