Beginner confusion about autowiring in Spring - spring

All:
I just begin the Spring study, there is one concept confused me so much: The Autowiring.
The question I need to be clear is:
What kind of thing can be autowired? Is it only other beans?
If I define a class Bar:
public class Bar {
#Autowired
public String name;
}
I am thinking what if I put a #Autowired annotation to a member variable like String name; and in bean config XML I wrote:
<bean id="bar" class="com.Bar">
<property name="name" value="Bar" />
</bean>
So many ways to do same thing in Spring confused me so much. ToT.
Is there any good trick to clearly remember and tell diff among different ways?
Thanks

Yes, You can only #Autowired Beans. #Autowired is the way of using Dependency Injection in Spring. It is provided for Beans - components wrote once and used many times. There's no sense using DI on String property and I think You get Exception.

You can't autowire in a String value like you have done.
By writing your XML bean declaration, what you have done is created a singleton instance of Bar with the name field set to the value of 'Bar'.
If you wanted to then use this Bar class elsewhere in your application (say in a class called Foo) you could do this:
public class Foo {
#Autowired
private Bar bar;
}
Spring would then inject your instance of Bar into your Foo class.
However because Bar is a singleton by default, no matter how many instances of Bar you autowired into different classes, you would have the same instance of Bar in all of them. So if you try and modify name in one class, it will change for all the other classes.
As a general rule of thumb, if your class has any mutable data (data that will be changed and updated), then your class is not something that you should be declaring for autowiring (because there will only ever be one instance of it inside your Spring application). It works better for things like DAO's and service classes. In answer to your first question, yes you can only autowire instances of classes (beans).
If you need to get a String/Integer/Long/Array/Mutable Data Type value from somewhere, configure a properties file, and read up how to use the org.springframework.beans.factory.config.PropertyPlaceholderConfigurer class with the #Value annotation.

Related

How Field Injection in Spring Boot works internally?

#Autowired
UserService userService;
What happens exactly inside `#Autowired annotation whether it uses Constructor Injection or Setter Injection. I know that it is field Injection.
I'm not asking How IOC or DI works, I'm asking How Field Injection in Spring Boot works internally?
Basically field inject is a type of injection (obviously), so Spring injects dependency based on field type and maybe some annotations (like #Qualifier).
How does it work?
When Spring creates a bean, there is a special Bean Post Processor org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
Each field marked with #Autowired is considered by spring as a dependency, so it must analyze these dependencies (by using reflection under the hood) and find a match from the application context for each field (by Type, qualifier if specified, etc.). Then it sets the value, right into the field, again by reflection.
I don't intend to start "holly-wars" here, but I'll just mention that I personally try to avoid using this type of injection because it effectively breaks encapsulation of dependencies, making the class with autowired fields non-unit testable.
For example if you have something like this:
#Component
class Foo {
#Autowired
private Bar bar;
public Foo() {} // no-arg construction that exists by default
}
#Component
class Bar {
}
Then when you create an instance of Foo by yourself (e.g. in unit-test) you have no clear way to supply the Bar dependency to Foo instance without relying on spring.
Constructor Injection solves this for example.

How to override a Spring #Autowire annotation and set a field to null?

I am a Spring neophyte who is working on a large Spring-based project that has extensive coupling between Spring beans. I am trying to write some integration tests that exercise subsets of the total application functionality. To do so, I'd like to override some of the autowiring.
For example, suppose I have a class
public class MyDataServiceImpl implements MyDataService {
#Qualifier("notNeededForMyDataServiceTest")
#Autowired
private NotNeededForMyDataServiceTest notNeededForMyDataServiceTest;
//...
}
and a context file with:
<bean id="myDataService"
class="MyDataServiceImpl">
</bean>
In my test, I have no need to use the notNeededForMyDataServiceTest field. Is there some way I can override the #Autowired annotation and set notNeededForMyDataServiceTest to null, perhaps in the XML file? I don't want to modify any of the Java classes, but I do want to avoid the (problematic) configuration of notNeededForMyDataServiceTest.
I tried doing:
<bean id="myDataService"
class="MyDataServiceImpl">
<property name="notNeededForMyDataServiceTest"><null/></property>
</bean>
That doesn't work. IntelliJ informs me "Cannot resolve property 'notNeededForMyDataServiceTest'", apparently because there are no getters and setters for that field.
I'm using Spring Framework 3.1.3.
The following configuration should work, I took the liberty of mixing in Java configuration
#Configuration
//This will load your beans from whichever xml file you are using
#ImportResource("classpath:/path/beans.xml")
public class TestConfigLoader{
// This will declare the unused bean and inject MyDataServiceImpl with null.
public #Bean(name="notNeededForMyDataServiceTest") NotNeededForMyDataServiceTest getNotNeededForMyDataServiceTest(){
return null;
}
... any other configuration beans if required.
}
And annotate your test class like so:
// In your test class applicationContext will be loaded from TestConfigLoader
#ContextConfiguration(classes = {TestConfigLoader.class})
public class MyTest {
// class body...
}
These could help:
Context configuration with annotated classes
Testing with #Configuration Classes and Profiles
Spring TestContext Framework
and profiles:
beans profile="..."
Introducing #Profile
You could create different beans definition in the XML configuration and then activate them using the -Dspring.profiles.active="profile1,profile2" env.
You're using the #Autowired mechanism wrong. The qualifier is not a property that you need to set. That's actually the name of a bean, so that the container will be able to choose one particular instance in case multiple beans of the same type are defined in the same context.
So the container will look for a bean of type NotNeededForMyDataServiceTest and the name (which would actually be the bean id in XML): notNeededForMyDataServiceTest.
What I think you want is to instruct the container to not inject anything in that field if no bean of type NotNeededForMyDataServiceTest is defined in the application context. That could be achieved simply by setting the required attribute of the annotation to false:
#Autowired(required = false)
NotNeededForMyDataServiceTest someOptionalDependency;
The only drawback of this approach would be that the container will never complain at runtime if there's nothing to inject in that field (and perhaps you would want this sanity check when your code runs in production).
If you don't want to make that dependency optional (or you can't edit that code for some reason), you'll need to provide a mock / null value for that field by setting that explicitly in your context. One option to do that would be to use Java configuration instead of XML (like in #Abe's answer) and another approach would be to make use of a factory bean which returns null (like in this question).

Why is there a need to specify the class in both the xml file and in the getBean() method in Spring

This might be an obvious but I'm having a hard time understanding why we need to define the class of a bean in two places....
From the spring reference manual...
...
<bean id="petStore"
class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
<property name="accountDao" ref="accountDao"/>
<property name="itemDao" ref="itemDao"/>
<!-- additional collaborators and configuration for this bean go here -->
</bean>
// retrieve configured instance
PetStoreServiceImpl service = context.getBean("petStore", PetStoreServiceImpl.class);
Shouldn't the xml fine be enough for the container to know the class of petStore?
You can use the following method:
context.getBean("petStore")
However, as this returns a java.lang.Object, you'd still need to have a cast:
PetStoreServiceImpl petstore = (PetStoreServiceImpl)context.getBean("petStore");
However, this could lead to problems if your "petStore" bean is not actually a PetStoreServiceImpl, and to avoid casts (which since the advent of Generics are being seen as a bit dirty), you can use the above method to infer the type (and let's spring check whether the bean you're expecting is really of the right class, so hence you've got:
PetStoreServiceImpl service = context.getBean("petStore", PetStoreServiceImpl.class);
Hope that helps.
EDIT:
Personally, I would avoid calling context.getBean() to lookup methods as it goes against the idea of dependency injection. Really, the component that uses the petstore bean should have a property, which can then be injected with the correct component.
private PetStoreService petStoreService;
// setter omitted for brevity
public void someotherMethod() {
// no need for calling getBean()
petStoreService.somePetstoreMethod();
}
Then you can hook up the beans in the application context:
You could also do away with the configuration via XML and use annotation to wire up your beans:
#Autowired
private PetStoreService petStoreService;
As long as you've got
in your spring context, the "petStore" bean defined in your application context will automatically be injected. If you've got more than one bean with the type "PetStoreService", then you'd need to add a qualifier:
#Autowired
#Qualifier("petStore")
private PetStoreService petStoreService;
There's no requirement to specify the class in the getBean() method. It's just a question of safety. Note there's also a getBean() that takes only a class so that you can just look up beans by type instead of needing to know the name.

Using a property as a qualifier for Dependency Injection in spring

Is it possible to #Autowire a bean by name (ie. use a #Qualifier) but get the name of the bean from a property set by the BeanFactoryPostProcessor. So in short something like this:
#Autowired
#Qualifier(#Value("${name.of.my.object}"))
private MyObject obj;
Assuming that there are more than one MyObject beans that have been created and there is a property called name.of.my.object=foo in my properties files read by the PropertyPlaceholderConfigurer
That would be nice, but I don't think you can do such a thing.
The closest I can think of is to define a bean alias in XML:
<alias bean="${name.of.my.object}" alias="myAlias"/>
and then refer to the alias in the qualifier:
#Autowired
#Qualifier("myAlias")
private MyObject obj;
Not very elegant, and I haven't actually tried it before, but I think it should work.

Autowiring Unmanaged Beans Annotated With #Component

I want to use #AutoWired to inject a non-managed bean configured with #Component into a managed bean. I'm pretty sure I have the configuration right, but for some reason I keep getting the exception:
No unique bean of type [foo.Baz] is defined: Unsatisfied dependency of type [class foo.Baz]: expected at least 1 matching bean
Based on the error, I'm guessing it's not able to find the Baz class, but I'm not sure why. It's my understanding that the context:spring-configured element in the XML config was supposed to allow me to do this. I also made sure to include the appropriate jar files (spring-weaving.jar and aspectjweaver.jar).
Here's a simple example of my set up.
My XML config:
<beans ...>
...
<context:annotation-config/>
<context:spring-configured/>
<context:component-scan base-package="foo"/>
<bean id="bar" class="foo.Bar"/>
...
</beans>
I have one managed bean:
package foo;
public class Bar {
#Autowired
private Baz baz;
public void setBaz(Baz baz) {
this.baz = baz;
}
...
}
And one unmanaged bean:
package foo;
#Component
public class Baz {
...
}
Is there something I'm missing?
EDIT: The log lists the beans its instantiating, and foo.Baz isn't one of them. I don't know why it's not picking up the #Component annotated class.
Because Bar is configured with xml, it can only be configured with xml. i.e. you can't mix them. So that "#Autowired" annotation on Baz is not getting picked up (none of the annotations would be). It is only when you add the spring annotation at class level that spring will listen to any of the other annotations.
What you'll need to do is in the xml configure the bean to be autowired by type, add a setter for that type and you'll achieve the desired behaviour.
<bean id="bar" class="foo.Bar" autowire="byType"/>
One more thing, when you annotate a bean with #Component it is a spring managed bean. Just because it is not created with xml does not mean it is unmanaged. An unmanaged bean is one you don't get from spring.
Bar and Baz are both spring managed. It is the mechanism you've chosen to define them that differs.
The previous response is not correct, in one aspect. You can autowire beans that are otherwise configured with xml.
From section 3.4.5 in http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html:
When using XML-based configuration metadata[2], you specify autowire mode for a bean definition with the autowire attribute of the element. The autowiring functionality has five modes. You specify autowiring per bean and thus can choose which ones to autowire.
You can autowire by name, type and constructor. There is a crude example of this here: http://www.java2s.com/Code/Java/Spring/AutoWiring.htm
The error is due to the sequence of beans defined in your XML config file.
As on your XML file, bean for bar is created first and then their dependent beans due to which #Autowired is not able to find baz.
You must first declare bean for baz and then for bar.

Resources