March 11, 2017

#Spring : 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.

@Autowired: 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. Items annotated with @Autowired do not have to be public.

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

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.


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.

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