When autowiring use would be beneficiary with example - spring

I have recently learned concept of autowiring in spring. When I was trying to understand in which particular scenarios spring autowiring can be useful
I came up with the below two reasons from one of the questions asked in our stakoverflow forum.
1.I wanted to read values from a property file and inject them into a bean. Only way I could figure out how to do this at start up of my app was to
wire the bean in XML (and inject the properties.) I ended up using the "byName" attribute (because the bean was also marked as #Component) and then
used #Autowired #Qualifier("nameIChose") when injecting the bean into another class. It's the only bean I've written that I wire with XML.
2.I've found autowiring useful in cases where I've had a factory bean making another bean (whose implementation class name was described in a system
property,so I couldn't define the all wiring in XML). I usually prefer to make my wiring explicit though;
Can any body please give me some code snippet example of the above situations that would make my understanding of autowiring more clearer?

Here is an example of injecting properties into a bean.
Using field injection:
#Component
public class YourBean {
#Value("${your.property.name}")
private String yourProperty;
}
Using constructor injection:
#Component
public class YourBean2 {
private String yourProperty;
#Autowired
public YourBeans2(#Value("${your.property.name}") String yourProperty) {
this.yourProperty = yourProperty;
}
}
The following is a super simple example of autowiring various beans
#Component
public class Foo {
public void doSomething() {
}
}
#Component
public class Bar {
private Foo foo;
#Autowired
public Bar(Foo foo) {
this.foo = foo;
}
public void doSomethingElse() {
foo.doSomething();
}
}
In the previous example, no XML configuration of Foo and Bar needs to be done, Spring automatically picks up the beans because of their #Component annotation (assuming of course that component scanning has been enabled)

Related

Conditionally auto-wire a bean implementation based on a value?

I have an interface Animal having two implementations Cat and Dog. These two implementations are spring #Component. How do I conditionally wire these two based on a value? I understand that I may have to change the scope of MyTestController from singleton to request.
#RestController
public class MyTestController {
#Autowired
Animal animal;// how to wire bean of Cat or Dog based on animalName
#PostMapping("/get-animal")
public #ResponseBody Animal getAnimal(#RequestParam(value = "animalName") String animalName) {
return animal;
}
}
Since both MyTestController is a bean the autowiring / initialisation happens before you actually start using the class instance itself. What I mean is that by the time you actually trigger REST requests on your controller, the injected animal bean should be already there!
More specifically if you have two classes that implement the same interface (Animal) without further specification (active Profiles, or #Primary annotation) Spring won't be able to decide which implementation to inject while creating the MyTestController,
What you want to do is return beans from your ApplicationContext based on a parameter / class name. This would look something like this:
#Autowired
private ApplicationContext context;
/* ... */
if(animalName.equals("dog") {
context.getBean(Dog.class) //returning the dog bean
} else if(animalName.equals("cat") {
context.getBean(Cat.class) //returning the cat bean
}
Edit IMO the question is a bit confusing. You ask for wiring the bean based on a value, but this value only comes at runtime. Hence my answer. However If you want to wire based on some variable at initialisation of your bean I would suggest taking a look at the following sources:
Profiles - With profiles you can tell spring which instance to inject in which configuration. (E.g.: production/development/test configs and for each you want to inject different beans)
Primary - One of your bean takes precedence over the others while injecting it.
Qualifier
Finally I would note that such an inversion on the IoC is considered as a bad practice. (See here)
Well, you're missing the whole point. Don't autowire simple DTO, but autowire AnimalFactory or some kind of AnimalRepository (or better - Service) where you can create or retrieve animals based on animal type.
It would look something like that:
#Component
public class AnimalFactory {
public Animal createAnimal(String animalType) {
switch (animalType) {
case "DOG":
return new Dog();
case "CAT":
return new Cat();
}
throw new IllegalArgumentException("AnimalType is invalid");
}
}
Animal Spring Data JPA Repository:
#Component
public class AnimalRepository implements JpaRepository<Animal, Long> {
public Optional<Animal> findByAnimalName(String animalName);
}

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 Autowired annotation with service implementation

I have few doubts in the scenario below.
Having one interface and two implementation classes:
Interface:
interface ServiceInt
{
public void save();
}
First implementation class:
Public class ServiceIntImpOne implements ServiceInt
{
public void save()
{
// I am first service implementation
}
}
Second implementation class:
Public class ServiceIntImpTwo implements ServiceInt
{
public void save()
{
// I am Second service implementation
}
}
Main class calling the save method of an implementation class:
Public class controller
{
#Autowired ServiceInt;
public void save()
{
ServiceInt.save()
}
}
My Questions:
ServiceInt.save() – which save method of service class implementation will it invoke?
How we can use the save method implementation of the ServiceIntImpTwo class?
How does autowired work?
ServiceInt.save() – which save method of service class implementation
will it invoke?
If you have two beans of the same type (beans defined via annotations or via xml) when you autowire that beans it will fail (throw exception), because Spring don't know what bean to inject.
caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
No unique bean of type [ServiceInt] is defined:
How we can use the save method implementation of the ServiceIntImpTwo
class?
If you defined your bean in a xml file, then you can use the id property
<bean id="beanTwo" class="ServiceIntImpTwo" />
then you can autowire using Qualifier annotation
#Autowired
#Qualifier("beanTwo")
ServiceInt myServiceTwo;
if you are using annotations instead.
#Component
Class ServiceIntImpTwo impl...{}
Then you can autowire
#Autowired
#Qualifier("serviceIntImpTwo ")
ServiceInt myServiceTwo;
How does autowired work?
This you can read it on Internet.
http://memorynotfound.com/handling-multiple-autowire-dependencies-with-spring-qualifier/
https://www.mkyong.com/spring/spring-autowiring-qualifier-example/
https://www.tutorialspoint.com/spring/spring_qualifier_annotation.htm
If you have two implementation to one interface you will need to provide spring hint which one to use:
you can use #Qaulifier annotation
you can use #Profile and choose the active profile.

Autowiring doubts in spring?

After going thru autowiring concept
i have got some questions. These are:-
If i need to autowire below class byType or byName , is it mandatory to have setStudent() method in class College?
public class College {
private Student student1;
private String registration1;
}
<bean id="student1" class="Student"/> - in case of byname it will look into id attribute and in case of bytype it will look for class attribute in above
Stetement. Right? If incase it finds two bean dean tags for the same type it will throw fatal error in case of bytype. Correct?
autodetect Scenario chooses constructor or byType through introspection of the bean class. If a default constructor is found, the byType mode
will be applied.
My question here if default constructor is not found and constructor with argument is found then autowire by constructor
will be applied. Correct?
Do we need to specify #Autowired somewhere in College to apply the autowiring. As i can see this in this example
but nothing is specified here
1), 4) There are two separate ways of autowiring in Spring: XML-based and annotaion-based.
XML-based autowiring is activated from XML config, as described here. In the end, it will call setter method, so setStudent() method is required here.
Annonation-based autowiring, on the other hand, is performed via reflection magic. It attempts to fill everything you mark with #Autowired annotation. In fact, it can set private field with no accessors, as in
public class Foo {
#Autowired private Thingy thing; // No getThing or setThing methods
private void doStuff() {
// thing is usable here
}
}
For #Autowired annotaion to work, you will need to define corresponding bean post-processor; it is done by adding the following line to xml config:
<context:annotation-config/>
Note, that these two autowiring methods are independant, and it is possible(but not recommended) to use them simultaneously. In that case, xml autowiring will override annotations.
2) In general, autowiring will fail, if it cannot find one and only one candidate for injection. So, in your case, it will fail with exception upon container creation. There are some fallback quirks, but in general it works reliably.
3) Yes, documentaion says so.
About byName and byType autowiring. While byName autowiring simply tries to match bean name (can be specified with id attribute), byType is a bit more complex than class attribute lookup. It searches beans by type, and it will match interfaces. Example:
public interface SomeService {
void doStuff();
}
public class SomeServiceImpl implements SomeService {
#Override public void doStuff() {
// Implementation
};
}
public class ServiceUser {
#Autowired
private SomeService someService; // SomeServiceImpl instance goes here
}
P.S. You are referencing two different versions of Spring in your question, 2.5 and 3.0. Autowiring behavior is same in both.
In Addition if you are using #Autwired annotation you need to mark the classes as candidates for autowiring. It should be done by using one of these annotations:
#Repository
#Service
#Component
#Controller
and of cause you can configure it in different scopes:
#Scope("prototype")
#Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
Hope it makes it more clear.

Resources