Pages

Monday, 31 March 2014

Lesson 03 - Annotations and Rest of the Story of Spring Beans

In this lesson we dig through spring's bean annotations in detail. Let us start with annotation based container configuration. You have already seen few examples in previous chapters related to this, anyhow I will start them from scratch (like framework reference did for us)

An alternative to XML based approach to define bean definitions is to use annotations. In this approach, configuration will be done in java class only.With the help of few BPP like RequiredAnnotationBeanPostProcessor and few annotations we extend the functionality of spring container. Remember when configuration is done via annotations and XML approach then XML approach will overwrite annotations config. To enable annotations and let container identify bean annotations we need to mark <context:annotation-config/> in the spring bean xml file. With this it looks for beans with special annotations and identify them as bean configurations.

@Required:
This annotations applied to bean property setter methods and ensures bean property is configured at the configuration time itself rather raising NullPointerExceptions when we access the bean. We see example on this along with next annotation called @Autowired

@Autowired:
This is replacement for tradition "autowire" attribute of <bean> element. This annotation can be applied to constructors, arbitrary methods with multiple arguments etc.. Good thing about this annotation is we can collect all beans of special type say "Employee" in a collection such as Set<Employee> or Employee[] and even Maps as long as expected key is "String" (i.e Map<String,Employee> map) in this case map's key will contain the name of the bean. Autowiring mechanism fails if container is not able to find a bean of given type/name but we can control this by setting "required" attribute of @annotation to set to false. Note, there is a huge difference between @Required and @Autowired(required=false). In earlier case we are setting the property need to be required otherwise respective exception will be thrown if property value is not set correctly. Where as in later case we are saying given property is not needed to auto wiring (if property is ignored then auto wiring can not be done). We could keep @Autowired for well known interfaces such as BeanFactory, ApplicationContext,  MessageSource etc.. with out any extra setup these interfaces will be resolved.. We see all of them in an example

now this example shows how to use above mentioned annotations and how ApplicationContext is autowired. We are printing inside the CinemaTheatre class and main method too to show same ApplicationContext is set in both places.

@Resource:
spring supports injection using JSR250 annotations such as @Resource which is widely used in JEE 5,6. It takes a name attribute to indicate the name of the bean to be injected. If no name attribute us given spring derives name from the setter method as shown in below example. That means, If no name attribute is specified explicitly, the default name is derived from the field name or setter method. In case of a field, it takes the field name; in case of a setter method, it takes the bean property name. In the below example name will be derived based on property name "movieFinder"
public class Test {

  private SimepleBean simpBean;

  @Resource
  public void setSimpleBean (MovieFinder simpBean) {
      this. simpBean = simpBean;
  }
}
@PostConstruct, @Perdestroy
as we discussed in previous chapter these are alternatives to custom init method and implementing InitializingBean, DisposableBean interfaces. It is always recommended to use custom init method or these annotations than implementing spring specific interfaces. Refer previous chapter to know more on this

Classpath Scanning and Managed Components

For every bean defined in bean configuration xml file results in a BeanDefinition object in spring container. Previous examples in this chapter allowed us to define dependencies using annotations while the main bean definition is still in XML. Annotations only allowed to define dependency injection part of the bean definitions. In this section we see alternative to define bean definitions using java classes only and a mechanism to inform container to scan through java packages for finding these bean definitions (classes)

@Component,@Repository, @Service, @Controller
Above 4 annotations informs spring container that class annotated with them is a special bean in container and to be managed by it. last 3 are specialised annotations of @Component to specifically designed for persistence, service, web/presentation layers respectively. For example classes marked with @Repository translates specific exceptions to spring exceptions (technology agnostic). To spring auto detect classes with those above annotations we need to make following setting in bean definitions file:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:context="http://www.springframework.org/schema/context"
     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">

   <context:component-scan base-package="org.example"/>
</beans>
 above context:component-scan enabled context:annotation-config. So no need to keep context:annotation-config if you already kept component-scan.The  AutowiredAnnotationBeanPostProcessor & CommonAnnotationBeanPostProcessor are both included implicitly when you use the component-scan element. That means that the two components are autodetected and wired together without any special configuration metadata provided in XML.

@Bean
Usually we define bean definition using <bean> element, an alternative is to use @Bean annotation (possibly with a name in brackets) to a method with in a class annotated with @Configuration annotation. Similarly we could use @Qualifier, @Scope, @Lazy can be used to define qualifier of the bean, to set the scope of the bean, to define lazy initialisation or not respectively.. interesting thing is we could write method with @Bean annotation in both spring components (controller,service, repository, component) or inside classes annotated with @Configuration. but the difference is, The @Bean methods in a Spring component are processed differently than their counterparts inside a Spring @Configuration class. The difference is that @Component classes are not enhanced with CGLIB. Within @Configuration classes @Bean methods create bean metadata references to collaborating objects. Methods are not invoked with normal Java semantics. In contrast, calling a method or field within a @Component classes @Bean method has standard Java semantics.


Providing name&scope for auto-detected components:


When container scans the package and found components and no default name is given then name of the bean is generated by BeanNameGenerator. Its default implementation is to give uncapitalized un qualified name of the class. If you want to provide default naming strategy then provide implement BeanNameGenerator and mark the class name like below:
<beans>
   <context:component-scan base-package="com.mastspring"
                           name-generator="com.mastspring.MyNameGenerator" />
</beans>
Similarly the default scope is "Singleton" but where as if you want to give specific scope then give it like scope ("prototype"). Below example covers all these topics:
here we covered all above annotations in one go. In future chapter we see more of @Service, @Controller, @Repository annotations there we go in depth discussion on them. For now @Component is enough to be understood. In above section we did not complete our discussion on @Bean, @Configuration annotation as next whole section describes that in details:

Java Based Container Configuration

@Bean and @Configuration annotations are key to define bean configuration using java classes. Typically in a class annotated with @Configuration represents a <beans> element and each method annotated with @Bean represents a <bean> element. We can use @Bean element in @Configuration as well as classes marked with @Component annotation. Hence below both are same:
@Configuration
public class MyConfig {
  @Bean
  public CookingService cService() {
      return new CookingServiceImpl();
  }
}
<beans>
  <bean id="cService" class="com.mastspring.CookingServiceImpl"/></beans>

Starting with Spring 3.0 we do have special class called AnnotationConfigApplicationContext which is same as ClasspathXMLApplicationContext but it receives classes marked with @Configuration/@Component annotations rather XML file as constructor parameter. If @Configuration classes are given then it itself registers as bean definition and all method inside that class (declared with @Bean) are registered as bean definitions. In case of @Component classes are provided to AnnotationConfigApplicationContext then they are registered as beans and all dependency injection metadata uses @Autowired wherever needed to inject bean dependencies. Now if you see the same above example things will be bit clearer now.


Deep discussion on @Bean (method level), @Configuration (class level) annotations:


In one line, @Bean annotations are equivalent <bean> elements. These @Bean annotations can be used in @Configuration/@Component classes as "method" level annotations. When you keep this annotation to a method, by default method name will be given a bean name (unless you provide a BeanNameResolver implementation). Bean annotation takes initmethod, destroymethod, autowire parameters to reflect exactly serving the same purpose of <bean> element. Similarly you can use @Scope to set the scope of this bean. In case if you want to give different name to bean (diff from methodname) then use "name" value (like @Bean (name="myName") something like this), if you keep array of names rather one name, they are all considered as alias names.
@Configuration annotation is a natural way to denote multiple bean definitions in a single class. It looks very natural in java where one bean calls another bean just like any other method/reference. But remember when methods are marked with @Bean and if you invoke them twice still you get only one reference (as default scope is singleton and only one instance will be created). This is not same as a java semantics. The whole magic comes from all @Configuration classes are subclassed at startup-time with CGLIB (a code generation library). In the subclass, the child method checks the container first for any cached (scoped) beans before it calls the parent method and creates a new instance. With recent spring releases CGLIB comes along with spring.


This explains everything we discussed so far...

Application Context > Bean Factory

In most of the cases we use ApplicationContext rather than BeanFactory because it provides more framework style functionality. It extends BeanFactory and add more functionality. Mostly we use ApplicationContext in declarative way (either by the use of ContextLoader classes (more on this we we see MVC) or as part of normal j2ee application statup so you should avoid using ApplicationContext in your code programatically which binds your code to spring framework. Following features are given to ApplicationContext to enhance features provided by BeanFactory:

1. Access to messages in i18n (internationalisation) style.
2. Access to resources using URLs, Files using ResourceLoader interface (more on this in next chapter)
3. Event publication to events implementing ApplicationListener interface.
4. Loading hierarchical contexts (where a specific context deals with specific layer of your application)

MessageSource:

ApplicationContext extends MessageSource interface to provide i18n style messages. It also provides HierarchicalMessageSource to provide message in more hierarchically. When an ApplicationContext is created, it searches for a special bean called MessageSource is defined in the context or not. This bean must have a namecalled "messageSource". If it cant find one it tries searching in the parent context until it finds one. If it cant find anything in the hierarchy an empty "DelegatingMessageSource" is instantiated. Spring provides two implementations of MessageSource called, StaticMessageSource, ResourceBundleMessageSource (both implement HierarchicalMessageSource to enable heirarchical messaging). When we have multiple lcoales, then locale resolution follows the exactly the same way JDK RsourceBundle follows.i.e if you want to resolve messages againts UK english then you need to keep fils as <file>_en_GB.properties rather jjust <file>.properties. Another powerful version of ResourceBundleMessageSource called ReloadableResourceBundleMessageSource which provide reading properties file from not just classpath but from any spring accessible location (more on this next chapter) and it supports hot reloading of message sources.


Event Publication:

Event handling in ApplicationContext handeled by ApplicationEvent, ApplicationListener interface. If any bean is implementing ApplicationListener then it will be notified whenver an ApplicationEvent gets published.Its a pure observer pattern implementation.Following example showshow you can create your own custom events in spring. To publish your custom event you need to use publishEvent() on ApplicationEventPublisher class. Usually you implement ApplicationEventPblisherAware by registering it as a bean




Resource Abstraction:

ApplicationContext is a ResourceLoader. This statement explains everything (though we have complete next chapter on this).ResourceLoader can be used to loa Resource objects. Which are rich versions of java.net.URL object infact internally Resource objects wrap using java.net.URL wherever needed.Technically a resource can be obtained from classpath, file, URL.In next chapter we see complete details on Resource loading.

Qualifiers (interesting topic to wrap this lesson)

Since auto wiring could have more than one objects to wire we could filter them with the help of @Qualifier annotation to a specific spring bean to narrow down. And you could write your own annotation and make use of <qualifier> xml element as well to make sure given bean will be configured. The @Qualifier can be used on specific arguments or constructor arguments. It can be applied on types collections as well. In the below example, I have explained it in detail:

In next chapter we take a close look at resource abstraction in full detail.



Previous Next

No comments:

Post a Comment