I am reading the spring 3.0.x reference documentation to understand Spring Autowired annotation:
3.9.2 #Autowired and #Inject
I am not able to understand the below examples. Do we need to do something in the XML for it to work?
EXAMPLE 1
public class SimpleMovieLister {
private MovieFinder movieFinder;
#Autowired
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
EXAMPLE 2
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
#Autowired
public void prepare(MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
How can the two classes be autowired implementing the same interface and using the same class?
Example:
class Red implements Color
class Blue implements Color
class myMainClass{
#Autowired
private Color color;
draw(){
color.design();
}
}
Which design method will be called? How do I make sure the design method of Red class will be called and not Blue?
TL;DR
The #Autowired annotation spares you the need to do the wiring by yourself in the XML file (or any other way) and just finds for you what needs to be injected where and does that for you.
Full explanation
The #Autowired annotation allows you to skip configurations elsewhere of what to inject and just does it for you. Assuming your package is com.mycompany.movies you have to put this tag in your XML (application context file):
<context:component-scan base-package="com.mycompany.movies" />
This tag will do an auto-scanning. Assuming each class that has to become a bean is annotated with a correct annotation like #Component (for simple bean) or #Controller (for a servlet control) or #Repository (for DAO classes) and these classes are somewhere under the package com.mycompany.movies, Spring will find all of these and create a bean for each one. This is done in 2 scans of the classes - the first time it just searches for classes that need to become a bean and maps the injections it needs to be doing, and on the second scan it injects the beans. Of course, you can define your beans in the more traditional XML file or with an #Configuration class (or any combination of the three).
The #Autowired annotation tells Spring where an injection needs to occur. If you put it on a method setMovieFinder it understands (by the prefix set + the #Autowired annotation) that a bean needs to be injected. In the second scan, Spring searches for a bean of type MovieFinder, and if it finds such bean, it injects it to this method. If it finds two such beans you will get an Exception. To avoid the Exception, you can use the #Qualifier annotation and tell it which of the two beans to inject in the following manner:
#Qualifier("redBean")
class Red implements Color {
// Class code here
}
#Qualifier("blueBean")
class Blue implements Color {
// Class code here
}
Or if you prefer to declare the beans in your XML, it would look something like this:
<bean id="redBean" class="com.mycompany.movies.Red"/>
<bean id="blueBean" class="com.mycompany.movies.Blue"/>
In the #Autowired declaration, you need to also add the #Qualifier to tell which of the two color beans to inject:
#Autowired
#Qualifier("redBean")
public void setColor(Color color) {
this.color = color;
}
If you don't want to use two annotations (the #Autowired and #Qualifier) you can use #Resource to combine these two:
#Resource(name="redBean")
public void setColor(Color color) {
this.color = color;
}
The #Resource (you can read some extra data about it in the first comment on this answer) spares you the use of two annotations and instead, you only use one.
I'll just add two more comments:
Good practice would be to use #Inject instead of #Autowired because it is not Spring-specific and is part of the JSR-330 standard.
Another good practice would be to put the #Inject / #Autowired on a constructor instead of a method. If you put it on a constructor, you can validate that the injected beans are not null and fail fast when you try to start the application and avoid a NullPointerException when you need to actually use the bean.
Update: To complete the picture, I created a new question about the #Configuration class.
Nothing in the example says that the "classes implementing the same interface". MovieCatalog is a type and CustomerPreferenceDao is another type. Spring can easily tell them apart.
In Spring 2.x, wiring of beans mostly happened via bean IDs or names. This is still supported by Spring 3.x but often, you will have one instance of a bean with a certain type - most services are singletons. Creating names for those is tedious. So Spring started to support "autowire by type".
What the examples show is various ways that you can use to inject beans into fields, methods and constructors.
The XML already contains all the information that Spring needs since you have to specify the fully qualified class name in each bean. You need to be a bit careful with interfaces, though:
This autowiring will fail:
#Autowired
public void prepare( Interface1 bean1, Interface1 bean2 ) { ... }
Since Java doesn't keep the parameter names in the byte code, Spring can't distinguish between the two beans anymore. The fix is to use #Qualifier:
#Autowired
public void prepare( #Qualifier("bean1") Interface1 bean1,
#Qualifier("bean2") Interface1 bean2 ) { ... }
Yes, you can configure the Spring servlet context xml file to define your beans (i.e., classes), so that it can do the automatic injection for you. However, do note, that you have to do other configurations to have Spring up and running and the best way to do that, is to follow a tutorial ground up.
Once you have your Spring configured probably, you can do the following in your Spring servlet context xml file for Example 1 above to work (please replace the package name of com.movies to what the true package name is and if this is a 3rd party class, then be sure that the appropriate jar file is on the classpath) :
<beans:bean id="movieFinder" class="com.movies.MovieFinder" />
or if the MovieFinder class has a constructor with a primitive value, then you could something like this,
<beans:bean id="movieFinder" class="com.movies.MovieFinder" >
<beans:constructor-arg value="100" />
</beans:bean>
or if the MovieFinder class has a constructor expecting another class, then you could do something like this,
<beans:bean id="movieFinder" class="com.movies.MovieFinder" >
<beans:constructor-arg ref="otherBeanRef" />
</beans:bean>
...where 'otherBeanRef' is another bean that has a reference to the expected class.
Related
My application context XML is simple:
<context:component-scan base-package="com.depressio.spring" />
In that package, I have my configuration:
package com.depressio.spring
#Configuration
#ComponentScan(basePackages = "com.depressio")
public class DepressioConfiguration
{
#Inject private ApplicationContext context;
}
Within com.depressio, there's a repository (DAO):
package com.depressio.dao;
#Repository
public class ParameterDAO
{
public Parameter getParameter(long ID) { ... }
}
... and a service where injection is working just fine (no NPE when parameterDAO is used):
package com.depressio.resource;
#Service
#Path("/depressio/parameters")
public class ParameterResource
{
#Inject private ParameterDAO parameterDAO;
#Path("{id}")
public Response getParameter(long parameterID)
{
return Response.ok(parameterDAO.getParameter(parameterID).legacyFormat()).build();
}
}
However, the legacyFormat() method call there constructs another object. Within that object, I have to inject a different DAO (also annotated with #Repository, though). That injection isn't working.
So, we have the original Parameter object:
package com.depressio.domain;
public class Parameter
{
...
public LegacyParameter legacyFormat()
{
return new LegacyParameter(this);
}
}
... and the LegacyParameter where the injection isn't working:
package com.depressio.domain.legacy;
public class LegacyParameter
{
#Inject private LegacyDAO legacyDAO;
....
public LegacyParameter(Parameter newParameter)
{
// NullPointerException when using the injected legacyDAO.
}
}
I've tried a few things, including:
Using an no-args constructor for LegacyParameter, then calling a populate method so I'm not using the injected DAO until after the object is constructed. This didn't work.
Injecting the LegacyDAO into the ParameterResource and passing it in. This worked, but isn't ideal since I have to pass it around a whole lot (which injection should help avoid, no?). It did prove that LegacyDAO is injectible... just not into LegacyParameter apparently.
Adding a #Service, #Component, or #Named annotation on LegacyParameter. All end up with the NullPointerException on the line I try to reference the injected legacyDAO.
What am I missing?
As Sotirios has pointed out, it can't work since you create a regular Java object and do not give Spring a chance to enhance it.
Either let Spring create objects for which you want to enjoy the Spring 'magic' (like setting #Inject dependencies etc).
Or create your own objects and set the dependencies yourself (yourObject.setDao(dao)).
That said, there are exceptional cases in which you still want to create your objects 'on the fly' by yourself but rely on Spring to inject dependencies to these objects. In this case you should call Spring explicitly:
LegacyParameter p = new LegacyParameter(...);
applicationContext.getAutowireCapableBeanFactory().autowireBean(p);
I don't think you really need it in your case.
(see this link inject bean reference into a Quartz job in Spring? for an example when this is really required).
In addition, I would advice to simplify your configuration.
Why do you use both xml-based and java-based configuration that do actually the same? In your example you could keep only one of them and have the same effect.
i want to use 2 different beans (Spring) for one JSF-Page. I do not like to write every method into one bean, so i tried to separate into two beans like JobEditDataBean and JobEditActionBean.
I want to use the JobEdiDataBean just as "Container" for my data objects and move the actionstuff (like saving, update etc.) to the action bean.
What i did by now (and what seems to work, but feels wrong) is the following:
public class JobEditDataBean{
#Autowired
JobEditActionBean actionBean;
// some objects...
#PostConstruct
public void init() {
actionBean.setJobEditDataBean(this);
// do something ...
}
}
public class JobEditActionBean{
JobEditDataBean dataBean;
// some objects...
}
Do you have any hints or tipps how this can be done better, nicer?
Indeed, you don't need to have one bean per each page. You can use as much beans you want for any page, it is fine, as whenever an expression like #{someMB} is found in your XHTML, JSF will find a bean with that name and create a new instance if necessary.
If you need to inject one bean to another, just use #Autowired already:
#Component
#Scope("request")
public class JobEditActionBean {
#Autowired
private JobEditDataBean dataBean;
#PostConstruct
public void init() {
// dataBean.youCanUseDataBeanMethodsHereAlready()
}
}
You just have to make sure both beans are in the Spring container (annotating them with #Component will do), and choosing the right scope for each one. Beware of the scopes of the beans which you are injecting, cause it usually only makes sense to inject beans of broader scope to beans of the same or more restrict scope.
Having said that, I recommend reading following thread about choosing the right scopes:
How to choose the right bean scope?
One more thing: this is only valid if your JSF beans are really being managed by the Spring container (that was my assumption after you used #Autowired). If you are letting JSF container manage the beans (using #ManagedBean with #RequestScoped or #ViewScoped, for example), the way you inject them is with a #ManagedProperty annotation:
...
#ManagedProperty("#{jobEditDataBean}")
private JobEditDataBean dataBean;
I want to create two beans of the same class through xml config file. The class has an annotated setter to be filled by spring. In one of the bean definitions I also provide value manually to override one from annotation. But when I do this, spring no longer handles annotation wiring.
Here is a minimal code to demonstrate this effect, used #Value for simplicity but it's the same with #Autowired:
import org.springframework.beans.factory.annotation.Value;
import javax.annotation.PostConstruct;
public class AutowireTest {
public String testField;
#PostConstruct
public void init() {
if (testField == null)
throw new RuntimeException("FAIL");
}
#Value("default")
public void setTestField(String testField) {
this.testField = testField;
}
}
and spring config:
<bean id="au_test1" class="AutowireTest">
<property name="testField" value="manual"/>
</bean>
<bean id="au_test2" class="AutowireTest"/>
If I remove <property name="testField" value="manual"/>, both beans receive "default". If it's there the second bean throws an exception. I had a look at spring code and AutowiredAnnotationBeanPostProcessor is using injectionMetadataCache where classes are keys for injection metadata meaning setting particular property for one bean disables autowiring for the other instances.
Any idea why it's this way? How can I achieve a similar effect working not necessarily for string values but also for object beans?
EDIT:
I want to have a property where there are multiple matching candidates. One is marked as primary. Unless I specify a candidate manually through xml, I would like to have the primary one wired. My original approach was to use #Autowired for this property but since this does not work I'm looking for an alternative. For some reason I don't want to use bean inheritance.
EDIT2:
If I swap these two bean definitions, the problem does not occur. The property is autowired fine until manual override is detected for the first time. This means this is not an intented feature since it can lead to weird and hard to detect bugs in some projects with dependencies not being wired as expected.
If you take a look at the javaDocs for the AutowiredAnnotationBeanPostProcessor, there is a note stating:
"Annotation injection will be performed before XML injection; thus the
latter configuration will override the former for properties wired
through both approaches."
This means that setting your beans property in xml with and with out a property value for "testField" makes a two new beans one where testField is set and one where it is null.
Its a one or the other thing. you can either use autowiring for a class or set it up manually in xml but cant do both. Im guessing that when your removing the property spring is just setting the same autowired bean to both names.
Once the beans of the same class are set up manually you can inject them into other beans using the #Qualifier("au_test1") annotation
In my opinion it is a bug in spring which I have submitted through jira. To work around this, annotation must be moved from setter to field. Setter must stay to allow manual overriding of the property. Possible setter logic (I know this should be avoided) should be moved to #PostConstruct. Adapted original code below:
import org.springframework.beans.factory.annotation.Value;
import javax.annotation.PostConstruct;
public class AutowireTest {
#Value("default")
public String testField;
#PostConstruct
public void init() {
if (testField == null)
throw new RuntimeException("FAIL");
}
public void setTestField(String testField) {
this.testField = testField;
}
}
Maybe, because of my wrong English, I couldn't understand the benefit of using #Autowired annotation.
According to the tutorial we can simplify the first(I.) case to second case(II.) by means of #Autowired.
My question is, what is the meaning of the #Autowired ? Because it doesnt tell any more, since without using #Autowired the compiler can figure out that "EmpDao emDao" and "EmpManager" are closely related according the declaration.
code cited from here
I.
<bean id="empDao" class="EmpDao" />
<bean id="empManager" class="EmpManager">
<property name="empDao" ref="empDao" />
</bean>
public class EmpManager {
private EmpDao empDao;
public EmpDao getEmpDao() {
return empDao;
}
public void setEmpDao(EmpDao empDao) {
this.empDao = empDao;
}
...
}
II.
<context:annotation-config />
<bean id="empManager" class="autowiredexample.EmpManager" />
<bean id="empDao" class="autowiredexample.EmpDao" />
import org.springframework.beans.factory.annotation.Autowired;
public class EmpManager {
#Autowired
private EmpDao empDao;
}
#Autowired is spring-specific. #Inject is the standard equivallent. It is an annotation that tells the context (spring, or in the case of #Inject - any DI framework) to try to set an object into that field.
The compiler has nothing to do with this - it is the DI framework (spring) that instantiates your objects at runtime, and then sets their dependencies at the points you have specified - either via XML or via an annotation.
I agree it is a possible scenario for a DI framework to try to inject dependencies into all fields, even if they are not annotated. (And if you want to exclude a particular field, to annotate it). But they chose the other strategy (configuration-over-convention). By the way:
if using xml config and choose some form of autowiring, the dependencies of the bean will be automatically autowired without the need to specify anything
you can specify per-context autowiring settings.
When the server bootstraps itself. It finds
<context:annotation-config />
in the application context and then goes through the classes defined in the contexts. If there are any beans that are autowired, it injects that into the class by referring the context file.
Basically, it promotes convention over configuration. That's what most frameworks do these days to reduce the development time.
the #Autowired Spring annotation tells Spring to for a bean named 'empDao' and inject it into the EmpManager class, without you having to add the empDao bean as a property in your spring config file.
#Autowired tells Spring to find a bean of the declared type and wire in that bean, rather than requiring an explicit lookup by bean name. It can, under certain circumstances, make configuring applications easier if you only have one implementation of your types in a given Spring context.
i have the following in my app-servlet.xml
<mvc:annotation-driven />
<context:component-scan base-package="com.merc.myProject.web.controllers"/>
<context:component-scan base-package="com.merc.myProject.web.forms"/>
what ever I have in my controller package gets injected but the same thing in the forms package is always null.
my form looks something like this
public class SelectDatesForm {
#Inject IUserService userService;
.....
}
my controllers looks like this
#Controller
public class SelectDates {
#Inject IUserService userService;
.....
}
somebody please help
<context:component-scan> looks for classes annotated with things like #Component, #Controller, #Service, and so on, and configures those as beans. If those classes have properties injected with #Inject or #Resource, then those will be processed also.
However, if your class isn't annotated to start with, then #Inject will not be processed. This is the case for SelectDatesForm. If you annotate this with #Component, it should get picked up.
I'd be a bit careful here, though - forms are generally not good candidates for Spring beans, since they tend to be throw-away, transient objects.
I guess your SelectDatesForm is instantiated manually with new rather than obtained from the Spring context. In this case it is not a Spring bean and therefore not a subject for dependency injection.
Usually you don't need to inject dependencies into manually created objects. If you actually need to do so, you have several options:
Declare your SelectDatesForm as a prototype-scoped bean and obtain a fresh instance of it from Spring context instead of creating it with new:
#Component #Scope("prototype")
public class SelectDatesForm { ... }
and when you need to obtain a new instance of it:
SelectDatesForm newForm = applicationContext.getBean(SelectDatesForm.class);
However, this approach couples your code with Spring's ApplicationContext.
If your have no control over instantiation of SelectDatesForm (i.e. it happens outside of your code), you can use #Configurable
Also you can manually facilitate autowiring of the object created with new:
SelectDatesForm newForm = new SelectDatesForm();
applicationContext.getAutowireCapableBeanFactory().autowireBean(newForm);