Uncategorized

Autowiring using annotations in spring

It’s a feature of spring framework by which spring automatically injects one dependency into the another dependency or in a more formal way we can say implicitly wires the two dependencies.BENEFITS/NO

Spring provides @Autowired annotation to achieve autowiring among beans.

Let’s understand the above description of autowiring through a simple example by comparing an example of dependency injection without autowiring and with autowiring.

Example:

Dependency injection without autowiring: I will use the same example from my previous tutorial on “Dependency injection with spring” where we injected an object as a dependency into a dependent class.

Phone.java

package com.geekslab.device;

public interface Phone {

public void openApp(int number);

}

BasicPhone.java

package com.codegeekslab.type;

import com.geekslab.os.Phone;

public class BasicPhone implements Phone {

@Override
public void openApp(int number) {
System.out.println("calling via simcard... " + number);
}

}

SmartPhone.java

package com.codegeekslab.type;

import com.geekslab.device.Phone;

public class SmartPhone implements Phone {

@Override
public void openApp(int number) {
System.out.println("calling via whatsapp..." + number);
}

}

CallingApp.java

package com.codegeekslab.app;

import com.geekslab.device.Phone;

public class CallingApp {

private Phone phone;

public CallingApp(Phone phone) {
this.phone = phone;
}

public void makeCall(int number) {
phone.openApp(number);
}

}

CellPhoneConfiguration.java


package com.codegeekslab.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import com.codegeekslab.app.CallingApp;
import com.codegeekslab.type.BasicPhone;
import com.codegeekslab.type.SmartPhone;
import com.geekslab.device.Phone;

@Configuration
public class CellPhoneConfiguration {

@Bean
public BasicPhone basicPhone() {
return new BasicPhone();
}

@Bean
public CallingApp callingApp(Phone phone) {

return new CallingApp(phone);
}

}

Test.java


package com.codegeekslab.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

import com.codegeekslab.app.CallingApp;
import com.codegeekslab.configuration.CellPhoneConfiguration;

public class Test {

public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.scan("com.codegeekslab.configuration");
context.refresh();
CallingApp callingApp = context.getBean("callingApp", CallingApp.class);
callingApp.makeCall(99999);

}
}

Output


Apr 02, 2017 12:52:43 PM org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@378fd1ac: startup date [Sun Apr 02 12:52:43 IST 2017]; root of context hierarchy
calling via simcard...99999

This was our previous example on dependency injection using java configuration file, where to create beans we had created a configuration file named CellPhoneConfiguration and manually defined all the beans using @Bean annotation.But spring Autowire feature provides a more easy way to implement the same example, where we don’t even have to write this configuration file and don’t even have to manually define all these beans using @Bean annotion by providing  spring .

Let me rewrite the above example using Autowiring-

Phone.java


package com.geekslab.device;

public interface Phone {

public void openApp(int number);

}

BasicPhone.java


package com.codegeekslab.type;

import org.springframework.stereotype.Component;

import com.geekslab.device.Phone;

@Component("BasicPhone")
public class BasicPhone implements Phone {

public void openApp(int number) {
System.out.println("calling via simcard... " + number);
}

}

CallingApp.java


package com.codegeekslab.app;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;

import com.geekslab.device.Phone;

@Component
public class CallingApp {

@Autowired
private Phone phone;

public void makeCall(int number) {
phone.openApp(number);
}

}

Test.java


package com.codegeekslab.test;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.codegeekslab.app.CallingApp;
import com.codegeekslab.type.BasicPhone;
import com.codegeekslab.type.SmartPhone;
import com.geekslab.device.Phone;

public class Test {

public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.scan("com.codegeekslab.app","com.codegeekslab.type");
context.refresh();
CallingApp callingApp = context.getBean("callingApp", CallingApp.class);
callingApp.makeCall(99999);

}
}

Output

[java]

Apr 15, 2017 3:13:54 PM org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@378fd1ac: startup date [Sat Apr 15 15:13:54 IST 2017]; root of context hierarchy
SmartPhone
calling via simcard... 99999

Let’s understand this application in a bit more detail.

@Component annotation in Spring

Unlike our previous example where we had created beans in a java configuration using @Bean annotation by placing over a method whose return type was the class for which we wanted to create a bean, here Spring provides another annotation named as @Component which provides an easy way other than @Bean annotation to create beans.Just place this bean on top of a class for which you want to create a bean.

As we require two beans in our application one is of CallingApp class and another of BasicPhone class, So to create these two beans we have placed this @Component annotation on top of these two classes.Now when spring container will search for beans in our application, as soon as it will encounter this @Component annotation on top of these two classes it will create beans of these two classes.

BasicPhone.java


@Component
public class BasicPhone implements Phone {

public void openApp(int number) {
System.out.println("calling via simcard... " + number);
}

}

CallingApp.java


@Component
public class CallingApp {

@Autowired
private Phone phone;

public void makeCall(int number) {
phone.openApp(number);
}

}

@Autowire annotation in Spring

Spring provides @Autowire annotation which implicitly and automatically wires two beans.Using @Autowire annotation spring wires two beans based on the type of bean or based on the name bean depending how you have defined the beans.it also depends on the number of beans present in the application which are of the same type.Let’s break down all these cases and understand it in more detail what I am trying to say here.

  • Case 1: if there is only one bean of a particular type.

 

In our above application, you can see there is only one implementation of Phone Interface which is Basic Phone.So that means there is only one bean named as basicPhone which is of type Phone.

Now as we want to inject or wire the type of Phone interface beans which is “basicPhone” into the bean of CallingApp class, to achieve that I have placed the @Autowired on the top of phone reference variable.When spring container while creation of the callingApp bean will come across this @Autowired annotation on top of Phone interface it will search into its container whether any beans which are of type Phone interface is present or not, And as we have already created a bean named as basicPhone which is of type Phone interface as it implements the Phone interface  satisfy this condition will get wired or injected into callingApp bean.


@Service
public class CallingApp {

@Autowired
private Phone phone;

}

And


@Component
public class BasicPhone implements Phone {

}

is equivalent to

CallingApp callingApp = new CallingApp(new BasicBean);

  • Case 2: If there are two beans of the same type.

Let’s create one more bean which is of type Phone.To do that I have created one more class named as SmartPhone and created a bean out of this class by marking this class with @Component annotation.


@Component
public class SmartPhone implements Phone {

public void openApp(int number) {
System.out.println("calling via WhatsApp..." + number);
}

}

So now we have two beans which are of the same type that is of Phone.Now here when spring container tries to wire a bean of type Phone into callingApp bean gets confused, because this time there two beans one is basicPhone and another smartPhone which is eligible to get wired with basicPhone.when you try to run the application you will get an exception unsatisfied dependency exception with message NoUniqueBeanDefinitionException: No qualifying bean of type [com.geekslab.device.Phone] is defined: expected single matching bean but found 2: smartPhone,basicPhone.

Output:


Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'callingApp': Unsatisfied dependency expressed through field 'phone': No qualifying bean of type [com.geekslab.device.Phone] is defined: expected single matching bean but found 2: basicPhone,smartPhone;

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.geekslab.device.Phone] is defined: expected single matching bean but found 2: basicPhone,smartPhone

To solve this problem we have to give the name of the bean to spring so that it understand which bean it has to wire into the callingApp bean.To achieve this, spring provides an annotation named as @Qualifier.

Note: In our previous post on Dependency Injection using Annotations in Spring Framework when we tried to add more than one bean which was qualified to get wired with callingApp bean we were thrown a UnsatisfiedDependencyException exception because the spring container got confused which bean to inject.The Same thing is happening here if I add one more bean of type Phone interface in my application  I will be thrown a UnsatisfiedDependencyException exception.

Resolving Ambiguities using Qualifier

To resolve the above UnsatisfiedDependencyException exception, spring provides @Qualifier(“name of the bean”) annotation.We have to place this annotation on top of a refrence variable along with @Autowire and pass the name of the bean into it.

Let’s add this annotation into our CallingApp class above the Phone reference variable and resolve this ambiguity.

CallingApp.java


@Component
public class CallingApp {

@Autowired

@Qualifier("basicPhone")
private Phone phone;

public void makeCall(int number) {
phone.openApp(number);
}

}

Now when spring sees this @Qualifier(“basicPhone”) annotation on top of “phone” reference variable it makes out that it has to wire the basicPhone and callingApp bean.

output


Apr 16, 2017 3:50:14 PM org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@378fd1ac: startup date [Sun Apr 16 15:50:14 IST 2017]; root of context hierarchy
calling via simcard... 99999

  • Case 3: If there are two beans of the same type but one of them has the same name as the name of refrence of the type.

If you keep your reference name same as the bean name then spring container won’t face any confusion or difficulty finding which bean it has to inject if there are more than one compatible beans are available for the injection.for an example consider the below sample application where I have kept the reference name same as the bean name which I want to inject.


@Component
public class CallingApp {

@Autowired

private Phone phone;

private Phone basicPhone;

public void makeCall(int number) {
phone.openApp(number);
}

}

In this case after seeing the name of the reference variable which is same as same as one of the beans in our application which in this case is “basicPhone”.In case if you want to inject the “smartPhone” bean then just change the name of the reference variable from “basicPhone” to “smartPhone”.

When you apply @Autowire on your beans it makes them mandatory to get wired with the eligible beans.But there will be times when you don’t want to make your beans mandatory to get wired with another bean.To make them not mandatory you can set the required property of @Autowired as false like this @Autowired(required=false)


@Component
public class CallingApp {

@Autowired(required=false)

private Phone phone;

private Phone basicPhone;

public void makeCall(int number) {
phone.openApp(number);
}

}

So for phone property even if Spring couldn’t find any matching bean it won’t throw any error and it leave this property unset.

Apart from placing over a reference variable, it can be placed on top of a setter method or a constructor like below and all will work equivalently.

On a set method-


@Service
public class CallingApp {

private Phone phone;

@Autowired                                                                                                                                                                                                   public void setPhone(Phone phone) {
this.phone = phone;
}

}

On top of a constructor-


@Autowired
public CallingApp(Phone phone) {
super();
this.phone = phone;
}

 

@Resource and @Inject in Spring

Java provides two alternatives to Spring’s @Autowire annotation. One is @Resource and another is @Inject.Both the annotations can be used interchangeably with @Autowire annotations.The benefits of these annotations are when you want to shift from Spring framework to another framework which implements the dependency injection framework you don’t have to make any changes if you are using these annotations as these belongs to java.  There are few differences between all these three.Let’s find out more about these annotations.

@Resource:  The resource annotation is from java javax.annotation package.it works exactly same as @Autowrired.


@Resource
public CallingApp(Phone phone) {
super();
this.phone = phone;
}

There are basically two differences when we compare it with @Autowired.

  • The first difference is you can provide the name of the bean as the property with @Resource.


@Resource(name="basicPhone")
public CallingApp(Phone phone) {}

@Resource(name=”basicPhone”) is equivalent to @Autowired with @Qualifier(“basicPhone”)

By this spring will be able to understand which bean it has to inject.

  • The second one is, like @Autowired annotation which provides a property @Autowired(required=false) which makes the bean injection optional if there are no beans present, @Resource doesn’t provide this option.

@Inject: The resource annotation is from java javax.inject package.it also works exactly same as @Autowired and @Qualifier.The only difference when we compare with @Autowired is it doesn’t have (required=false) option present.

However, there is one more difference if you know “scope in beans” which I have covered here, the default scope for @Autowired beans is Singleton whereas using JSR 330 @Inject annotation has a scope as a prototype.

Spring @Component, @Repository, @Service and @Controller Annotations

Apart from @Component which allows us to create beans, Spring provides few more @Components like annotations through which we can create beans which are @Repository,@Service, and @Controller.These beans can be used interchangeably with @Component.Consider our previous example where we created a bean of CallingApp class using @Component.Now When I replace @Component with @Repository, @Service or @Controller it get the same output.


@Repository //you can replace this with @Service and @Controller also
public class CallingApp {

@Autowired(required=false)

private Phone phone;

private Phone basicPhone;

public void makeCall(int number) {
phone.openApp(number);
}

}

Difference between  @Component, @Repository, @Service and @Controller Annotation.

All these annotations are used to create beans and works same like @Component but have some little extra features.In a multitier application, we have different kinds of layer like repository service and controller.Repository layer into which we write code related to persistence or saving the data into a database.Service layer into which we write business logic like calculations.Controller layer which generally acts as a mediator between repository and service layer.Spring has created these annotations according to these layers and recommends to use appropriate annotations at these layers to create beans.Like @Repository at Repository layer classes, @Service at Service layer classes and @Controller at Controller layer classes to create beans.

To understand the major differences between them you need to know Spring AOP and Spring MVC which I have covered later and I recommend to learn Spring AOP and MVC before jumping into understanding the differences between them.In case you know spring AOP and Spring MVC you can find the in detail differences between them in this post.

Leave a Reply

Your email address will not be published. Required fields are marked *