Issue
I have a little question about bean creation that bothers me a lot.
For example I have classes
public class A {
B b;
public A(B b) {
this.b = b;
}
}
public class B {}
And I want to make beans for them like this:
@Configuration
public class Config {
@Bean
public B beanB() {
return new B();
}
//version 1
@Bean
public A beanA() {
return new A(beanB())
}
//version 2
@Bean
public A beanA(B beanB) {
return new A(beanB)
}
}
So, my question is what is the right way to create bean A?
I think that the right one is version 2, because in the version 1 I think beanB can be invoked 2 times: on the creation of beanA and when spring will create it for it's context. But I can't find anything that will prove my opinion.
Solution
The "right" way is to do it the way the documentation, i.e. the javadoc of @Bean
, shows it:
@Bean
Methods in@Configuration
ClassesTypically,
@Bean
methods are declared within@Configuration
classes. In this case, bean methods may reference other@Bean
methods in the same class by calling them directly. This ensures that references between beans are strongly typed and navigable. Such so-called 'inter-bean references' are guaranteed to respect scoping and AOP semantics, just likegetBean()
lookups would. These are the semantics known from the original 'Spring JavaConfig' project which require CGLIB subclassing of each such configuration class at runtime. As a consequence,@Configuration
classes and their factory methods must not be marked as final or private in this mode. For example:@Configuration public class AppConfig { @Bean public FooService fooService() { return new FooService(fooRepository()); } @Bean public FooRepository fooRepository() { return new JdbcFooRepository(dataSource()); } // ... }
That means version 1 in the question code.
Spring dynamically subclasses AppConfig
, so only one instance is created no matter how many times the method is called, e.g. functionally something like this:
public class $dynamic$ extends AppConfig {
private FooRepository cachedFooRepository;
@Override
public FooRepository fooRepository() {
if (this.cachedFooRepository == null)
this.cachedFooRepository = super.fooRepository();
return cachedFooRepository;
}
}
Answered By - Andreas
Answer Checked By - Dawn Plyler (JavaFixing Volunteer)