`@Configuration` doc improvements

Various documentation improvements related to `@Configuration` and
`Bean`. Better describe how method parameter can be used to declare
dependencies of a particular bean. Also add an explicit mentions related
to "hard-wiring" of dependencies in configuration classes.

Issue: SPR-12773
This commit is contained in:
Stephane Nicoll 2015-03-09 16:26:41 +01:00
parent 8f8a85912a
commit c7fcf7cd4c
1 changed files with 83 additions and 7 deletions

View File

@ -5644,10 +5644,6 @@ The `AppConfig` class above would be equivalent to the following Spring `<beans/
</beans> </beans>
---- ----
The `@Bean` and `@Configuration` annotations will be discussed in depth in the sections
below. First, however, we'll cover the various ways of creating a spring container using
Java-based configuration.
.Full @Configuration vs 'lite' @Beans mode? .Full @Configuration vs 'lite' @Beans mode?
**** ****
When `@Bean` methods are declared within classes that are __not__ annotated with When `@Bean` methods are declared within classes that are __not__ annotated with
@ -5665,6 +5661,9 @@ accidentally being invoked multiple times and helps to reduce subtle bugs that c
hard to track down when operating in 'lite' mode. hard to track down when operating in 'lite' mode.
**** ****
The `@Bean` and `@Configuration` annotations will be discussed in depth in the sections
below. First, however, we'll cover the various ways of creating a spring container using
Java-based configuration.
[[beans-java-instantiating-container]] [[beans-java-instantiating-container]]
=== Instantiating the Spring container using AnnotationConfigApplicationContext === Instantiating the Spring container using AnnotationConfigApplicationContext
@ -5916,6 +5915,31 @@ transferService -> com.acme.TransferServiceImpl
---- ----
[[beans-java-dependencies]]
==== Bean dependencies
A `@Bean` annotated method can have an arbitrary number of parameters describing the
dependencies required to build that bean. For instance if our `TransferService`
requires an `AccountRepository` we can materialize that dependency via a method
parameter:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@Configuration
public class AppConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
----
The resolution mechanism is pretty much identical to constructor-based dependency
injection, see <<beans-constructor-injection,the relevant section>> for more details.
[[beans-java-lifecycle-callbacks]] [[beans-java-lifecycle-callbacks]]
==== Receiving lifecycle callbacks ==== Receiving lifecycle callbacks
Any classes defined with the `@Bean` annotation support the regular lifecycle callbacks Any classes defined with the `@Bean` annotation support the regular lifecycle callbacks
@ -6366,12 +6390,64 @@ issue, per se, because there is no compiler involved, and one can simply declare
Of course, when using `@Configuration` classes, the Java compiler places constraints on Of course, when using `@Configuration` classes, the Java compiler places constraints on
the configuration model, in that references to other beans must be valid Java syntax. the configuration model, in that references to other beans must be valid Java syntax.
Fortunately, solving this problem is simple. Remember that `@Configuration` classes are Fortunately, solving this problem is simple. As <<beans-java-dependencies,we already discussed>>,
`@Bean` method can have an arbitrary number of parameters describing the bean
dependencies. Let's consider a more real-world scenario with several `@Configuration`
classes, each depending on beans declared in the others:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@Configuration
public class ServiceConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
@Configuration
public class RepositoryConfig {
@Bean
public AccountRepository accountRepository(DataSource dataSource) {
return new JdbcAccountRepository(dataSource);
}
}
@Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig {
@Bean
public DataSource dataSource() {
// return new DataSource
}
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
// everything wires up across configuration classes...
TransferService transferService = ctx.getBean(TransferService.class);
transferService.transfer(100.00, "A123", "C456");
}
----
There is another way to achieve the same result. Remember that `@Configuration` classes are
ultimately just another bean in the container - this means that they can take advantage ultimately just another bean in the container - this means that they can take advantage
of `@Autowired` injection metadata just like any other bean! of `@Autowired` injection metadata just like any other bean!
Let's consider a more real-world scenario with several `@Configuration` classes, each [WARNING]
depending on beans declared in the others: ====
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 example above.
====
[source,java,indent=0] [source,java,indent=0]
[subs="verbatim,quotes"] [subs="verbatim,quotes"]