March 11, 2017

#Spring part 5 : Annotations

Spring provides support for annotation based container configuration.


@Required: It is applied on setters of the attributes of bean, which are mandatory, i.e specifies that a particular property must be injected or else the configuration will fail. Suppose you have an Employee bean, which has 'employee id', then you need to import @Required  from org.springframework.beans.factory.annotation.Required and add it before your setter method, e.g

@Required
public void setEmpId(String empId) {
    this.empId = empId;
}


And in the spring.xml you need to add,
< bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" / >

After doing this, the "empId" property must be injected or else Spring will throw a BeanInitializationException and context creation will fail.

What are different types of Spring Bean autowiring?
  • autowire byName – For this type of autowiring, setter method is used for dependency injection. Also the variable name should be same in the class where we will inject the dependency and in the spring bean configuration file.
  • autowire byType – For this type of autowiring, class type is used. So there should be only one bean configured for this type in the spring bean configuration file.
  • autowire by constructor – This is almost similar to autowire byType, the only difference is that constructor is used to inject the dependency.
  • autowire by autodetect – If you are on Spring 3.0 or older versions, this is one of the autowire options available. This option was used for autowire by constructor or byType, as determined by Spring container. This option is now deprecated.
  • @Autowired annotation –Spring @Autowired annotation can be used for spring bean autowiring. This annotation can be applied on constructors, variables and methods for autowiring byType. For @Autowired annotation to work, we also need to enable annotation based configuration in spring bean configuration file. This can be done by context:annotation-config element or by defining a bean of type org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.
  • @Qualifier annotation – This annotation is used to avoid conflicts in bean mapping and we need to provide the bean name that will be used for autowiring. This way we can avoid issues where multiple beans are defined for same type. This annotation usually works with the @Autowired annotation. For constructors with multiple arguments, we can use this annotation with the argument names in the method.

What is Bean wiring and @Autowired annotation?
The process of injection spring bean dependencies while initializing it called Spring Bean Wiring. Usually it’s best practice to do the explicit wiring of all the bean dependencies, but spring framework also supports autowiring by @Autowired annotation.This can be applied to Constructor, Field or on a Method.

With this annotation, we can declare a constructor, field, setter method, or configuration method to be autowired by type.

Suppose, you are have developed a class which draws a circle. Since Circle has a center, we which create a Point class:
public class Point {   
    private int x, y;
    // getter, setters of x and y
}


Now we will create a Circle class, with a Point as a member variable and a draw method. Since we want to autowire the center, so we will declare @Autowired before the setter method of Circle:

public class Circle{
    private Point center;
    public void draw() {
        System.out.println("Drawing circle...x="+center.getX()+", y="+center.getY());
    }   
    @Autowired
    public void setCenter(Point center) {
        this.center = center;
    }
    //getter of center..
}


In the spring.xml, we will declare two beans, one with id=center and other is circle.

AutowiredAnnotationBeanPostProcessor should be added, so that Spring can autowire the Point with Center, also the 'id' of Point bean should be same as member variable declared in Circle.java (which is here center)

'id' of Point bean
< beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd"
    xmlns:context="http://www.springframework.org/schema/context" >
< bean id="center" class="com.test.Point" >
    < property name="x" value="0" / >
    < property name="y" value="1" / >
< /bean >
< bean id="circle" class="com.test.Circle" >
< /bean >
< bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" / >
< /beans >


Now, whenever you call the draw method, 'Point' bean will be autowired with 'Circle':

AbstractApplicationContext  context=new ClassPathXmlApplicationContext("beanPostProcessorSpring.xml");
Circle circle=(Circle)context.getBean("circle");
circle.draw();
//this will print: Drawing circle...x=0, y=1



@Qualifier : Suppose, because of some reason we cannot change the 'id' of Point bean in spring.xml, then we need to use @Qualifier annotation. It guides autowiring to be performed by means other than by type.

In the Circle bean, we need to make following changes:
@Autowired
@Qualifier ("circleRelated")
public void setCenter(Point center) {
    this.center = center;
}


And in the spring.xml:
< bean id="centerPoint" class="com.test.Point" >
    < qualifier value="circleRelated" / >
    < property name="x" value="0" / >
    < property name="y" value="1" / >
< /bean >
< bean id="circle" class="com.test.Circle" / >   


The qualifier name which we have set in the settler method of bean, should be same as qualifier value in spring.xml

What are the different ways through which we can autowire a spring bean?
  • autowire byName – For this type of autowiring, setter method is used for dependency injection. Also the variable name should be same in the class where we will inject the dependency and in the spring bean configuration file.
  • autowire byType – For this type of autowiring, class type is used. So there should be only one bean configured for this type in the spring bean configuration file.
  • autowire by constructor – This is almost similar to autowire byType, the only difference is that constructor is used to inject the dependency.
  • autowire by autodetect – If you are on Spring 3.0 or older versions, this is one of the autowire options available. This option was used for autowire by constructor or byType, as determined by Spring container. Since we already have so many options, this option is deprecated. I will not cover this option in this tutorial.
  • @Autowired annotation – We can use Spring @Autowired annotation for spring bean autowiring. @Autowired annotation can be applied on variables and methods for autowiring byType. We can also use @Autowired annotation on constructor for constructor based spring autowiring. For @Autowired annotation to work, we also need to enable annotation based configuration in spring bean configuration file. This can be done by context:annotation-config element or by defining a bean of type org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.
  • @Qualifier annotation – This annotation is used to avoid conflicts in bean mapping and we need to provide the bean name that will be used for autowiring. This way we can avoid issues where multiple beans are defined for same type. This annotation usually works with the @Autowired annotation. For constructors with multiple arguments, we can use this annotation with the argument names in the method.

JSR-250 Annotations: In addition to Spring's own set of annotations, Spring also supports a few of the annotations defined by JSR-250 (Java Specification Request). JSR-250 is an standard that defines all the standard annotations which can be applied across different technologies and different framework.

@Resource: It indicates that a method or field should be injected with a named resource (by default, another bean).

public class Circle{   
    private Point center;
    public void draw() {
        System.out.println("Drawing circle...x="+center.getX()+", y="+center.getY());
    }
    public Point getCenter() {
        return center;
    }
    @Resource(name="point3")
    public void setCenter(Point center) {
        this.center = center;
    }
}

In spring.xml
< bean id="circle" class="com.test.Circle" >
< /bean >   
< bean id="point3" class="com.test.Point" name="point3" >
    < property name="x" value="0" >
    < property name="y" value="20" >
< /bean >

If you do not specify the 'name' in setCenter(), then it will look for bean with same name as member variable (i.e. 'center')

@PostConstruct: Indicates a method to be invoked after a bean has been created and dependency injection is complete. Used to perform any initialization work necessary.

@PreDestroy: Indicates a method to be invoked just before a bean is removed from the Spring context. Used to perform any cleanup work necessary.

What is a Controller in Spring MVC?
Controller is the class that takes care of all the client requests and send them to the configured resources to handle it. In Spring MVC, org.springframework.web.servlet.DispatcherServlet is the front controller class that initializes the context based on the spring beans configurations.

A Controller class is responsible to handle different kind of client requests based on the request mappings. We can create a controller class by using @Controller annotation. Usually it’s used with @RequestMapping annotation to define handler methods for specific URI mapping.

Component and Stereotype Annotations


Spring @Component, @Service, @Repository and @Controller annotations are used for automatic bean detection using classpath scan in Spring framework.

With @Component we can declare the class as a bean, without any declaration in spring.xml.

@Component
public class Circle{   
    @Override
    public void draw() {
    System.out.println("Drawing circle...");
    }
}


In the spring.xml, we need to remove the bean declaration and add below lines (where the base-package is the package in which Circle class is present):
< context:component-scan base-package="com.test" / >
< context:annotation-config / >


@Service, @Repository, @Controller are stereotypes annotations, they are special cases of @Component and used for particular purposes.

In a multitier application, we will have different layers like presentation, service, business, data access etc. When a class is to be annotated for auto-detection by Spring, then we should use the respective stereotype as below.
  • @Component – generic and can be used across application.
  • @Service – annotate classes at service layer level.
  • @Controller – annotate classes at presentation layers level, mainly used in Spring MVC.
  • @Repository – annotate classes at persistence layer, which will act as database repository. Also indicates that SQLExceptions thrown from the component's methods should be translated into Spring DataAccessExceptions. The postprocessor automatically looks for all exception translators (implementations of the PersistenceExceptionTranslator interface) and advises all beans marked with the @Repository annotation so that the discovered translators can intercept and apply the appropriate translation on the thrown exceptions.
What’s the difference between @Component, @Controller, @Repository & @Service annotations in Spring?
  • @Component is used to indicate that a class is a component. These classes are used for auto detection and configured as bean, when annotation based configurations are used.
  • @Controller is a specific type of component, used in MVC applications and mostly used with RequestMapping annotation.
  • @Repository annotation is used to indicate that a component is used as repository and a mechanism to store/retrieve/search data. We can apply this annotation with DAO pattern implementation classes.
  • @Service is used to indicate that a class is a Service. Usually the business facade classes that provide some services are annotated with this.

How can you disable automatic scan of @Component, @Repository, @Service, @Controller?
The automatic scan behavior can be disabled for the default stereotypes by setting the use-default-filters property to false.
< context:component-scan base-package="com.test" use-default-filters = "false" / >


-K Himaanshu Shuklaa..

No comments:

Post a Comment

RSSChomp Blog Directory