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
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
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
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
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:
Post a Comment