What would be the best alternative to avoid having both constructor and field injections?
As I understand, field injections are not recommended and constructor is the way to go. (http://olivergierke.de/2013/11/why-field-injection-is-evil/)
Please find here below where class A is being created inside @Configuration
bean and class B is created as a constructor param in class A.
However, class A needs other beans also to operate such as C/D/E which in turn has got their own autowired dependencies. I'm confused how to apply best recommended approach here.
Any suggestions, please let me know.
@Configuration
class Config {
@Bean
public A create_A() {
A = new A(new B());
}
}
class A {
B b;
@Autowired
C c;
@Autowired
D d;
@Autowired
E e;
A(B b) {
this. b = b;
}
}
class C {
@Autowired
Y y;
}
In general @Autowired
annotation has appeared in Spring 2.5 and later on in Spring 3.0 they've introduced "Java DSL" for configuration, the way of configuration with @Configuration
annotation and @Bean
annotated method.
If you work with @Configuration
like in your example of class A, then you don't really have to use @Autowired
. You also don't need annotations like @Component
if you manage everything via @Configuration
.
So, assuming you doubt how to inject classes like B
or C
into class A
without autowired assuming the class A
is defined via @Configuration
, you can do the following:
@AllArgsConstructor // I've used lombok - it will create a constructor with B and C for you, but you can define the constructor in java as well
public class A {
private final B b;
private final C c;
...
}
@Configuration
public class MyConfiguration {
@Bean
public A a(B b, C c) {
return new A(b,c);
}
@Bean
public B b() {
return new B();
}
@Bean
public C c() {
return new C();
}
}
Another alternative is using explicit method calls in the @Configuration
:
@Configuration
public class MyConfiguration {
@Bean
public A a() { // note, as opposed to the previous example, no parameters here
return new A(b(),c()); // note the explicit calls
}
@Bean
public B b() {
return new B();
}
@Bean
public C c() {
return new C();
}
}
This method won't work however if B
and/or C
were defined in the different @Configuration
file or via @Component
annotation
Note, that class A
doesn't have any Autowired fields, everything is injected via the constructor. Basically class A
now doesn't have any spring related annotations at all.
Now, if you don't use configurations for B
and C
, for example, you still can put @Component
on them and this will still work, because Spring "gathers" the information about what beans should be created and it has multiple resources to "obtain" this kind of information: via class scanning of classes annotated with @Component
, via @Bean
-s defined in the configuration, and so forth.
Even if you don't manage the class A
the constructor injection will still work:
@Component
@AllArgsConstructor // if there is only one constructor in the class, spring will use it for autowiring automatically, so no need to put @Autowired even on the constructor for recent spring versions
class A {
private final B b;
private final C c;
}
@Component
class B {
}
@Component
class C {
}