How can I access Spring beans in no-arg constructor? - spring

#Component
public class MyClass {
public MyClass() {
SomeInterface something;
// Spring magic that i don't know
something.toString();
}
}
What Spring magic do I need to use to inject a bean into "something"?
I also wouldn't mind if it was a field. It just has to be usable from within the constructor!

The basic rules also apply to Spring:
to construct an object, Spring needs to invoke the constructor
Spring can't call a method of an object or set one of its fields if it isn't constructed yet
so if you want to access a field set by Spring , you can't do that from the constructor, unless the value is passed as argument to the constructor.
This thus leaves two choices:
constructor injection:
#Autowired
public MyClass(SomeInterface something) {
// use something
}
post-construct method, called after all the injections have been done, whatever the way:
#Autowired
private SomeInterface something;
#PostConstruct
private void initialize() {
// use something
}

Related

Not able to inject values in a field

#Component
#PropertySources({ #PropertySource("classpath:mail.properties") })
public class A implements B {
#Value("${mail.team.address}")
private String teamAddress;
// has getter and setters .not shown for brevity.
Now when i call the class i get the value of teamAddress as NULL .But in the property file mail.team.address has some value.
My property file is present under src/main/resource folder
Making a call
A a = new A ();
a.someMethodinClassA();
You can not create instance of class by yourself when you want Spring to resolve #Value annotation.
See documentation:
Note that actual processing of the #Value annotation is performed by a BeanPostProcessor which in turn means that you cannot use #Value within BeanPostProcessor or BeanFactoryPostProcessor types. Please consult the javadoc for the AutowiredAnnotationBeanPostProcessor class (which, by default, checks for the presence of this annotation).
Simple solution for you: just annotate class with any #Component annotation and let Spring to create an instance of your class.
You can't create (with a "new" keywoard) for spring bean. If you do it like this, spring doesn't participate in the object creation and configuration, which means that there is no autowiring, the bean is not in Application Context, etc. And of course, #Value annotation won't be processed among other things
The better way is to inject the class A to the code that you used in your example:
A a = new A ();
a.someMethodinClassA();
Show become:
#Component
public class SomeClass {
private final A a;
public SomeClass(A a) {
this.a = a;
}
public void foo() {
a.someMethodinClassA();
}
}
You should read some basics around spring dependency injection. The class that you have autowired with #Component is scanned via component scanning and its object is created by spring container for you.
that is the reason you should not create the object yourself using new keyword.
wherever in your new class you want to use your class A object you can autowire it as below:
#Component
public class TestC{
private A a; // this object will be injected by spring for you
}

Is #Autowired taking care of the nested autowiring?

I have the following components, in two different files:
#Component
public class Chauffeur {
Car car;
public Chauffeur(Car car){
this.car = car;
}
public void go(){
System.out.println("Chauffeur");
car.drive();
}
}
#Component
public class Car{
public void drive() {
System.out.println("Drive car");
}
}
the following configuration file:
#Configuration
#ComponentScan
public class DriveableConfiguration {
}
and the following test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=DriveableConfiguration.class)
public class DriveableTest {
#Autowired
Chauffeur chauffeur;
#Test
public void chauffeurTest(){
chauffeur.go();
}
}
All the classes above are in the same package and the test is passing.
In the test I annotated chauffer with #Autowired, which should mean that the Spring container looks after the creation of the instance of Chauffeur without the developer needing to explicitly instantiate it.
Now, the constructor for Chauffer needs an instance of Car, so there is no default constructor for that class. Nonetheless the container creates it, injecting the required instance in the constructor.
Is the #Autowired saying to the container to instantiate the element with whatever (Components, Beans) it can provide, included parameters in the constructor? If so, in what case is it needed to use #Autowired to annotate a constructor?
Only if you use Spring 4.3+. In such a case #Autowired on constructor is optional if you have one non default constructor.
You can check the example here.
So as of 4.3, you no longer need to specify an explicit injection annotation in such a single-constructor scenario. This is particularly elegant for classes which otherwise do not carry any container annotations at all, for example when programmatically registered
For versions lower than 4.3 you will an exception will be thrown:
the container will throw an exception looking for a default
constructor, unless you explicitly indicate autowire mode
‘constructor’ in your bean definition setup (e.g. in an XML )

Spring Bean: Is autowired attribute initialised before constructor?

#Component
public class BeanA {
...
}
#Component
public class BeanB {
#Autowired
BeanA beanA;
public BeanB() {
// Use beanA
beanA.method();
}
}
Can we assume BeanA is created and initialized before BeanB constructor is called? (I know we can pass BeanA as constructor arg to BeanB, this is more of curiosity question to understand spring/java initialisation sequence)
Take a look at http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-autowired-annotation-qualifiers
Setting properties on bean would happen after it is constructed by means of a constructor or a factory method. By default, beans are autowired by name and values are set using setter methods. So in your case the field will be set after constructor.
This is because
#Autowired
BeanA beanA;
really means that you want to autowire the field of that class instance. beanA in your case is not really a constructor arg.
(Well, here is a quick question, are the constructor argument names retained after compilation? Is there any debug flag related to this?)
As this example from spring documentation says, you can apply #Autowired to constructors and fields:
public class MovieRecommender {
#Autowired
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
#Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
Let me know if you need any more help with this.
Oh, and just a minor point. You seem to be calling method() on beanA in your constructor. It is not a good idea, if the method can be overridden. I know it is just an example you jotted down here, but just a word of caution.
No, the autowiring is handled by a BeanPostProcessor that will run after the constructor of the newly created bean. If, for some reason, you need to autowire some fields and then run some initialisation you can use a #PostConstruct annotated method. It will be called after all dependencies are injected. In most cases #Autowiring a constructor (and, perhaps, making the object immutable) is still the best option.
No, spring is very clever, but not that magical ... Internally, spring :
creates an instance
set instances properties
stores eventually the bean in relevant scope (exept for prototype beans) and/or gives it to caller
But the creation uses a constructor and at the time it is called properties have not been set.
In short, you can access #Autowired in your method marked with #PostConstruct.

How can I make sure a "pool" bean gets all the other beans it needs?

I have a spring config where I define hundreds of actions which extend MyAction. I have a pool where an execution service can look up actions. I can't use the appContext directly because each action has one or more "keys" which the execution service will use and pool cuts that dependency.
So the pool must be able to collect all beans of type MyAction (or rather beans that extend MyAction).
The method ApplicationContext.getBeansOfType() seems to do what I need but when can I safely call it?
It would be great if I could call it in a #PostConstruct method but is it guaranteed that the bean factory has seen added each and every bean from the config at that time?
Note: Almost all of my beans are #Lazy
You could use injection by constructor and passing a Collection of yours MyAction
Something like
#Component
public class Foo {
private final Set<MyAction> myActions;
#Inject
public Foo(Set<MyAction> myActions) { this.myActions = myActions; }
}
or
public class Foo {
private Set<MyAction> myActions;
#Inject
public void setMyActions(Set<MyAction> myActions) { this.myActions = myActions; }
}
Spring will take care of creating the set with all beans that extends MyAction.
In the first case, they are injected by constructor, you can safely use them in any method.
In the second case, Spring will eventually call the setter. You can either do any post processing in the setter or add a #PostConstruct method that works on myActions.
Try to use ListableBeanFactory like this. Also here is API documentation. Method getBeansOfType has parameter allowEagerInit which forces eager init of lazy object.

Does a Spring annotated controller necessarily need a default constructor

I have a spring controller that uses annotations. I gave this controller a constructor that takes two arguments. I want both ways of initializing the controller: constructor injection and setter injection.
#Controller("viewQuestionController")
#RequestMapping("/public/viewQuestions")
public class ViewQuestionController
{
#Resource(name="questionService")
private QuestionService questionService;
/*public ViewQuestionController()
{
int i=0;
i++;
}
*/
public ViewQuestionController(#Qualifier("questionService") QuestionService questionService)
{
this.questionService = questionService;
}
#Resource(name="questionService")
public void setQuestionService(QuestionService questionService)
{
this.questionService = questionService;
}
}
When I uncomment the default constructor, the controller is initiated correctly. However, if I don't, I get a BeanInstantiationException, No default constructor found; nested exception is java.lang.NoSuchMethodException.
So, is my configuration for the annotated constructor wrong or does a completely annotated controller in spring always need a default constructor?
If you want to configure constructor injection via annotations, you need to put the corresponding annotation on the constructor. I'm not sure how it can be done with #Resource, but #Autowired and #Inject support it:
#Autowired
public ViewQuestionController(#Qualifier("questionService") QuestionService questionService)
or
#Inject
public ViewQuestionController(#Named("questionService") QuestionService questionService)
I think Controller beans need a default constructor as they are initialized by the framework but there is no way to tell the framework hot to provide the dependency.
On second thought why not you autowire your question service and Spring will take care of it.
The following code should be good
#Controller("viewQuestionController")
#RequestMapping("/public/viewQuestions")
public class ViewQuestionController
{
#Autowired
private QuestionService questionService;
//Not providing any constructor would also be fine
public ViewQuestionController(){}
questionService will be initialized properly by Spring

Resources