In Spring, you can use @Autowired annotation to auto-wire bean on the setter method, constructor , or a field . Moreover, it can autowire the property in a particular bean. We must first enable the annotation using below configuration in the configuration file.
You need to specify this bean in the constructor: @Component public class MainClass { private final AnotherClass anotherClass; // this annotation is NOT required if there is only 1 constructor, shown for clarity. @Autowired MainClass(AnotherClass anotherClass) { this.
Is @Autowired annotation mandatory for a constructor? No. After Spring 4.3 If your class has only single constructor then there is no need to put @Autowired .
This mode is very similar to byType, but it applies to constructor arguments. Spring container looks at the beans on which autowire attribute is set constructor in the XML configuration file. It then tries to match and wire its constructor's argument with exactly one of the beans name in the configuration file.
You need the @Value
annotation.
A common use case is to assign default field values using
"#{systemProperties.myProp}"
style expressions.
public class SimpleMovieLister {
private MovieFinder movieFinder;
private String defaultLocale;
@Autowired
public void configure(MovieFinder movieFinder,
@Value("#{ systemProperties['user.region'] }") String defaultLocale) {
this.movieFinder = movieFinder;
this.defaultLocale = defaultLocale;
}
// ...
}
See: Expression Language > Annotation Configuration
To be more clear: in your scenario, you'd wire two classes, MybeanService
and MyConstructorClass
, something like this:
@Component
public class MyBeanService implements BeanService{
@Autowired
public MybeanService(MyConstructorClass foo){
// do something with foo
}
}
@Component
public class MyConstructorClass{
public MyConstructorClass(@Value("#{some expression here}") String value){
// do something with value
}
}
Update: if you need several different instances of MyConstructorClass
with different values, you should use Qualifier annotations
Well, from time to time I run into the same question. As far as I know, one cannot do that when one wants to add dynamic parameters to the constructor. However, the factory pattern may help.
public interface MyBean {
// here be my fancy stuff
}
public interface MyBeanFactory {
public MyBean getMyBean(/* bean parameters */);
}
@Component
public class MyBeanFactoryImpl implements MyBeanFactory {
@Autowired
WhateverIWantToInject somethingInjected;
public MyBean getMyBean(/* params */) {
return new MyBeanImpl(/* params */);
}
private class MyBeanImpl implements MyBean {
public MyBeanImpl(/* params */) {
// let's do whatever one has to
}
}
}
@Component
public class MyConsumerClass {
@Autowired
private MyBeanFactory beanFactory;
public void myMethod() {
// here one has to prepare the parameters
MyBean bean = beanFactory.getMyBean(/* params */);
}
}
Now, MyBean
is not a spring bean per se, but it is close enough. Dependency Injection works, although I inject the factory and not the bean itself - one has to inject a new factory on top of his own new MyBean
implementation if one wants to replace it.
Further, MyBean
has access to other beans - because it may have access to the factory's autowired stuff.
And one might apparently want to add some logic to the getMyBean
function, which is extra effort I allow, but unfortunately I have no better solution. Since the problem usually is that the dynamic parameters come from an external source, like a database, or user interaction, therefore I must instantiate that bean only in mid-run, only when that info is readily available, so the Factory
should be quite adequate.
In this example, how do I specify the value of "constrArg" in
MyBeanService
with the@Autowire
annotation? Is there any way to do this?
No, not in the way that you mean. The bean representing MyConstructorClass
must be configurable without requiring any of its client beans, so MyBeanService
doesn't get a say in how MyConstructorClass
is configured.
This isn't an autowiring problem, the problem here is how does Spring instantiate MyConstructorClass
, given that MyConstructorClass
is a @Component
(and you're using component-scanning, and therefore not specifying a MyConstructorClass
explicitly in your config).
As @Sean said, one answer here is to use @Value
on the constructor parameter, so that Spring will fetch the constructor value from a system property or properties file. The alternative is for MyBeanService
to directly instantiate MyConstructorClass
, but if you do that, then MyConstructorClass
is no longer a Spring bean.
You can also configure your component like this :
package mypackage;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConstructorClassConfig {
@Bean
public MyConstructorClass myConstructorClass(){
return new myConstructorClass("foobar");
}
}
}
With the Bean
annotation, you are telling Spring to register the returned bean in the BeanFactory
.
So you can autowire it as you wish.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With