Monday, January 29, 2018

Spring Annotations


Introduction to J2EE Annotation



Annotation is the code about the code that is metadata about the program itself. In other words information about the code is provided at the source code. Annotations are parsed/processed by compilers, annotation-processing tools and also executed at runtime.

Annotations have been introduced in JDK 1.5. It allows the programmers to specify the information about the code at the source code level itself. There are several ways we can use annotations. Few helps in understanding the source code (like documentation assistance) @override is the annotation that will be used when we override a method from base class. This annotation doesn’t have any impact on run-time behavior, rather it helps javadoc compiler to generate documentation based on it.

Apart from these annotations we have another way in using annotations which assist source code generators to generate source code using them. If we take example as Web Services, in order to expose a class as web service, we need to mark the class as @WebService. This annotation would be read by a tool and generates class to expose that class as web service.

Along with this there is another way, where when you mark a class with annotation, the run-time engine will executes the class based on that annotation with which it marked. For example, when you mark a class with @EJB, the class would be exposed as Enterprise Java Bean by the container rather than a simple pojo.

By the above we can understand that using annotations, a programmer can specify the various behavioral aspects of your code like documentation, code generation and run-time behavior. This helps in RAPID application development where in instead of specifying the information about your code in xml configuration file, the same can be specified by marking your classes with annotations.

Note: Always your annotation configuration will be overwritten with the xml configuration if provided.


Spring Annotation Support



Spring support to annotations is an incremental development effort. Spring 2.0 has a very little support to annotation, when it comes to spring 2.5; it has extended its framework to support various aspects of spring development using annotations. In spring 3.0 it started supporting java config project annotations as well.

The journey to spring annotations has been started in spring 2.0; it has added @ Configuration, @Repository and @Required annotations. Along with this it added support to declarative and annotation based aspect AOP.

In spring 2.5 it has added few more annotations @Autowired, @Qualifier and @Scope. In addition in introduced stereotype annotations @Component, @Controller and @Service.

In spring 3.0 few more annotations has been added like @Lazy, @Bean, @DependsOn etc. In addition to spring based metadata annotation support, it has started adoption JSR - 250 Java Config project annotations like @PostConstruct, @PreDestroy, @Resource, @Inject and @Named etc.

The below table list spring supported and Java Config project supported annotations.


Working with @Configuration and @Bean



Instead of declaring a class as spring bean in a configuration file, you can declare it in a class as well. The class in which you want to provide the configuration about other beans, that class is called configuration class and you need to annotate with @Configuration. In this class you need to provide methods which are responsible for creating objects of your bean classes, these methods has to be annotated with @Bean.

Now while creating the core container, instead of using XMLBeanFactory, you need to create it using AnnotationConfigApplicationContext by passing the configuration class as input.


AppConfig.java



@Configuration
public class AppConfig {
    @Bean 
    Public MyService myService() {
      return new MyServiceImpl();
    }
}  


MyService.java



public class MyService {
     public void doSomeStuff() {
                 // some dummy logic
     }
}


ConfigurationTest.java



ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
MyService myService = ctx.getBean(MyService.class);
myService.doSomeStuff();


Working with @Required



In spring 1.x onwards we have dependency check. For a bean if you want to detect unresolved dependencies of a bean, you can use dependency check. In this IOC container will check whether all the bean dependencies, which is expressed in its properties are satisfied or not. The problem with dependency check is you can’t impose restriction on a certain property, either you need to check the dependencies on all simple or object or all.

In 2.0, it has introduced an annotation @Required and dependency check has been completely removed in 2.5. Using @Required annotation you can make, a particular property has been set with value or not.


Engine.java



package com.annotation.beans;
   public class Engine {
          private Integer id;
          private String type;
          
          public Integer getId() {
                 return id;
          }

          @Required
          public void setId(Integer id) {
                 this.id = id;
          }

          public String getType() {
                 return type;
          }

          public void setType(String type) {
                 this.type = type;
          }
   }

You can use @Required on a setter level to mark it as mandatory. Simply using @Required annotation will not enforce the property checking, you also need to register an RequiredAnnotationBeanPostProcessor in the configuration file as shown below.


application-context.xml



<bean id=”engine” class=”com.annotation.beans.Engine”>
         <property name=”id” value=”22”/>
         <! - -if you don’t provide value for id, raises error - ->
         <property name=”type” value=”T1”/>
         <qualifier value=”myengine”/>
   </bean>
   (<context:annotation-config/>

   (OR)

   <bean class=”org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor”

   />)


Working with @Autowire



You can enable autowiring using @Autowire annotation rather than configuration approach. Unlike your declarative etc, in annotation driven we don’t have any modes.

In annotation based approach you may mark an attribute of a target class or a setter or a constructor or any arbitrary method for injecting the dependent object. In all the cases it will performs autowiring byType.

@Autowired annotation has an attribute required=true (@Autowired(required=true)). By default required is true. When you use required=true, while creating the target class object it will try to find the appropriate dependent class object in IOC container, if it couldn’t find one the container will throws exception without creating core container.

At any point of time out of available number of constructors, you can mark only one constructor with @Autowired(required=true) and remaining should be set to false.

Below examples shows various ways of using @Autowired


Attribute Level




package com.annotation.beans;
   
   import org.springframework.beans.factory.annotation.Autowired;
   
   public class Motor {
          @Autowired(required=false)
          private Engine engine;
          
          public void run() {
                 System.out.println(running with engine id :  + engine.getId());
          }
   }


Setter Level




public class Motor {
          private Engine engine;
         
          @Autowired(required=false)
          public void setEngine(Engine engine) {
                 this.engine = engine;
          }
   ....
   }


Constructor Level



public class Motor {
          private Engine engine;
          
          @Autowired(required=false)
          public Motor(Engine engine) { 
                 this.engine = engine;
          }
   ....
   }


Arbitrary method




public class Motor {
          private Engine engine;
             
          @Autowired(required=false)
          Public void newEngine(Engine engine) { 
                 this.engine = engine;
          }
   ....
   }


application-context.xml



<bean id=”engine” class=”com.annotation.beans.Engine”>
        <property name=”id” value=”22”/>
        <property name=”type” value=”T1”/>
  </bean>
  
  <bean id=”motor” class=”com.annotation.beans.Motor”/>
  <context:annotation-config/>

In order to detect @Autowire either you need to use or need to declare a bean whose class is
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.


Working with @Qualifier



If you have more than one beans of type Engine in the configuration, as @Autowire will perform injection byType, it will not be able to make the decision of which bean has to be injected and will raise ambiguity error. To resolve this we need to perform byname, this can be done with @Qualifier as shown below.


Using Qualifier



public class Motor {
          private Engine engine;
          
          @Autowired(required=false)
          @Qualifier(engine2)
          Public void setEngine(Engine engine)
                 this.engine = engine;
   }
   }


application-context.xml



<bean id=”engine” class=”com.annotation.beans.Engine”>
         <property name=”id” value=”22”/>
         <property name=”type” value=”T1”/>
         <qualifier value=”myengine”/>
   </bean>
   <bean id=”maruthiengine” class=”com.annotation.beans.Engine”>
         <property name=”id” value=”22”/>
         <property name=”type” value=”T1”/>
         <qualifier value=”engine2”/>
   </bean>

   <bean id=”motor” class=”com.annotation.beans.Motor”/>
   <context:annotation-config/>

Only the bean whose qualifier value is “engine2” will be injected into Motor class engine attribute, so indirectly using @Qualifier we are able to perform byname injection.


Working with stereotype annotations @Component, @Repository, @Service and @Controller



In addition to @Repository annotation in spring 2.0, spring 2.5 has added stereotype annotations @Component, @Service and @Controller to make your classes as spring beans.

When you mark you class with any of the above annotations those classes will be exposed as spring beans by the container. Based on the type of class you are trying to expose you need to use appropriate annotations.

@Component – This acts as a more generic stereotype annotation to manage any component by spring, whereas the other annotations are specialized for the specific use cases.

@Repository – This is used for exposing a DAO class as a spring bean. Even though database specific semantics are not imposed by using it, it helps you in applying exception translations on these @Repository classes using AOP.

@Service – The service layer class are annotated with @Service, even though the current release of the spring doesn’t has any impact on using it (other than exposing that class as spring bean), but future releases of spring might add some specializations on those classes.

@Controller – When you make a class with @Controller, it will be exposed as spring MVC controller to handle form submissions.

In a spring core/spring jdbc applications you can use @Component, @Service or @Repository whereas @Controller can be used only in a spring MVC application.

The below examples shows how to use @Component, but you can mark that class with @Service or @Repository as well, where the end effect would be same.


Motor.java



@Component(motor)
   public class Motor {
          private Engine engine;
          
          @Autowired(required=false)
          public void setEngine(Engine engine) {
                 this.engine = engine;
          }
   .
   } 

With the above configuration, the class will be exposed as spring bean with id “motor”. In order to detect the @Component or stereotype you need to use the tag as shown below.

application-context.xml



You can retrieve the bean with context.getBean(“motor”).


Spring Java Config annotations



As explained earlier from spring 3.x it has added support to Java Config annotation support, this means when you mark you classes with any of the above discussed annotations like @Component or @Autowired, you classes will be tightly coupled with spring framework and will lose invasive feature of spring.

In order to retain loosely coupled feature, it spring has added support to java annotations, so when we use these annotations in spring applications, those will be read by spring container and add spring specific behavior to your classes. If you use in J2EE environment, those will behave based on container specification.


Working with @Inject



@Inject is a j2ee specific annotation, used for injecting/autowiring one class into another. This is more similar to @Autowired spring annotation. But the difference between them is @Autowire supports required attribute where @Inject doesn’t has it.

@Inject also injects a bean into another bean byType as similar to @Autowired. The advantage of @Inject is it from java (javax.inject package) which means even you separate your application from spring, still your classes can work with java rather than bounded to spring.


Motor.java



@Component(motor)
   public class Motor {
          private Engine engine;
          
          @Inject
          public void setEngine(Engine engine) {
                 this.engine = engine;
          }
   .
   }

Along with this you need to use to detect it by core container.


Working with @Named



There are two usages of @Named annotation

1) When you try to inject a bean using @Inject annotation it will performs injection byType, if you have more than one beans of that type in the application, the container will throw ambiguity error. In order to resolve it you need to use @Named annotation.


application-context.xml



<bean id=”engine” class =”com.annotation.beans.Engine”>
         <property name=”id” value=”22”/>
         <property name=”type” value=”T1”/>
         <property value=”myengine”/>
   </bean>
   <bean id=”maruthiengine” class=”com.annotation.beans.Engine”>
         <property name=”id” value=”22”/>
         <property name=”type” value=”T1”/>
   </bean>

   <bean id=”motor” class=”com.annotation.beans.Motor”/>
   <context:component-scan base-package=”com.annotation.*”/>

In the above configuration you have two beans of type Engine, so when you try to inject the Engine into Motor by using @Inject, it will not be able to detect which bean has to be injected. So you need to mark the Engine attribute with @Named along with @Inject indicating the bean you want to inject show below.


Motor.java




@Component("motor")
   public class Motor {
          private Engine engine;
          
          @Inject
          @Named(maruthiengine)
          public void setEngine(Engine engine) {
                 this.engine = engine;
          }
   .
   }

2) Another use of @Named is instead of using the stereotype annotations of spring to expose your classes as spring beans, you can mark your class with @Named to expose it as spring bean show below.


Motor.java



@Named(motor)
   public class Motor {
          private Engine engine;
          
          @Inject
          public void setEngine(Engine engine) {
                 this.engine = engine;
          }
   .
   }


Working with @Resource



Instead of using @Inject, you can also use @Resource, the difference between @Inject and @Resource it @Inject will perform the injection byType where as @Resource will perform the injection byname.


Motor.java



@Named(motor)
   public class Motor {
          private Engine engine;
             
          @Resource
          public void setEngine(Engine engine) {
                 this.engine = engine;
          }
   .
   }

So, we need to have a bean whose id is “engine” in the configuration or with the component declaration with this name.


application-context.xml



<bean id=”engine” class=”com.annotation.beans.Engine”>
         <property name=”id” value=”22”/>
         <property name=”type” value=”T1”/>
         <qualifier value=”myengine”/>
   </bean>
   <context:component-scan base-package=”com.annotation.*”/>


Working with @PostConstruct and @PreDestroy



As we discussed, Bean Lifecycle you can perform Initialization on a bean after injecting the dependent objects using init-method declaration or InitializingBean interface afterPropertiesSet and Destruction on a bean while removing a bean from core container using detroy-method or DisposableBean interface destroy() method.

Along with the above two ways, you can mark any arbitrary method on a class with @PostConstruct and @PreDestroy annotations. When you mark a method with @PostConstruct annotation, this method will be invoked by core container after injecting the dependent objects into the bean. When you mark a method with @PreDestroy annotation, this method will be invoked as part of bean destruction process.

So, the @PostConstruct and @PreDestroy or annotation based lifecycle methods.


Motor.java



@Named(motor)
   public class Motor {
          private Engine engine;
             
          @PostConstruct
          public void init() {
                 // I will be invoked after performing injection
          }

          @Resource
          public void setEngine(Engine engine) {
                 this.engine = engine;
          }
         
          @PreDestroy
          public void release() {
                 // I will be invoked while I am removing from container
          }
   .
   }

No comments: