mercoledì 16 maggio 2012

Core Spring and IOC concept in a nut. 1




Core Spring API Components

Spring is a container and component model. Everything else, including AOP, transactions, database access, web applications, and the like is built on top of this container and component model. Objects managed in the container do not have to know about Spring or the container because of Inversion of Control (IoC)

This pattern specifies the involvement of the Spring container (which manages lifecycle), your object, and any other dependant objects – known as beans in Spring parlance. 

The container is able to inject any number or type of dependant beans together while specifying the relationship throughconfiguration

Dependency injection is enabled by creating properties and matching setter methods of your target object for the types of objects that you expect to inject. Alternatively, objects may be injected
during instantiation by providing a constructor with a signature that matches types you expect to inject.

The core of Spring framework’s functionality lies within this IoC container, which is discussed next.

The Inversion of Control Container

The Inversion of Control (IoC) container provides the dependency injection support to your applications that enables you to configure and integrate application and infrastructure components together. Through IoC, your applications may achieve a low-level of coupling, because all of the bean
configuration can be specified in terms of IoC idioms (such as property collaborators and constructors). Meanwhile, most if not all of your application’s bean lifecycle (construction to destruction) may be managed from within the container. 

This enables you to declare scope – how and when a new object
instance gets created, and when it gets destroyed. 

For example, the container may be instructed that a
specific bean instance be created only once per thread, or that, upon destruction, a database bean may disconnect from any active connections. 
Through requests to the Spring IoC container, a new bean may
either get constructed or a singleton bean may get passed back to the requesting bean. Either way, this is a transparent event that is configured along with the bean declaration.


Spring Container Metadata Configuration

Spring provides several implementations of the ApplicationContext interface out of the box. In standalone applications using XML metadata (still commonplace today), it is common to create an
instance of 

org.springframework.context.support.ClassPathXmlApplicationContext or
org.springframework.context.support.FileSystemXmlApplicationContext.

Configuration metadata consisting of bean definitions represented with XML or Java configuration is preferred for third-party APIs for which you do not have access to source code. 

In most other cases, configuration metadatain addition to, or in place of XML – may be applied through Java annotations. 

ioc_basics.xml – 

A Basic Spring Application Configuration 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
<bean class="com.iocbasics.BasicPOJO"/>
 
</beans>

This is a simple XML document that makes use of the Spring beans namespace – the basis for resolving your POJO within the Spring container. 

Instantiating the IoC Container

To instantiate the IoC container and resolve a functional ApplicationContext instance, the relevant  ApplicationContext implementation must be invoked with a specified configuration. 

With a standard Java application with XML metadata configuration, the ClassPathXmlApplicationContext will resolve any number of Spring XML configuration resources given a path relative to the base Java classpath. This constructor is overloaded with a variety of argument arrangements that provide ways to specify the resource locations. 

Spring also provides a number of other applicationContext implementations. For example, FileSystemXmlApplicationContext is used to load XML configuration from the file system (outside of the classpath), and AnnotationConfigApplicationContext supports loading annotated Java classes.
 
In the next part of code, the context constructor is given a single resolvable path of the Spring configuration XML file. If the XML resource were located outside of classpath, the absolute file system path would be provided to the FileSystemApplicationContext factory class to obtain the ApplicationContext.

BasicIoCMain.java 
– Single Line of Code to Startup you Application Context

ApplicationContext ctx = new ClassPathXmlApplicationContext("ioc_basics.xml");

The next step is to obtain your configured beans. 

Simply calling ApplicationContext.getBean method (by passing it the class of the instance you want returned) will provide, by default, the singleton instance of the bean

That is, every bean will be the same instance.
BasicIocMain.java - Obtaining a Bean Reference by Class.

BasicPOJO basicPojo = ctx.getBean(BasicPOJO.class);

Alternatively, Spring can infer which bean definition your looking for by passing it the ID (or qualifier) of the bean instance instead of the bean class. This helps when dealing with multiple bean definitions of the same type. 

For instance, given a bean definition of the same BasicPojo class, The next sample illustrates the combined code effort in setting up and obtaining this bean resource.

BasicIocMain.java – Obtaining a Bean Reference by Name

BasicPOJO basicPojo = (BasicPOJO)ctx.getBean("basic-pojo");



Bean Instantiation from the IoC Container
 
A basic operation in a Spring context is instantiating beans. This is done in a variety of ways; however, we will focus on the most common use cases. 

In this example, the BasicPojo bean provides both a noarg and arguments-based constructor. In addition, we have a POJO property named color with type ColorEnum (see later). 

We will use both BasicPOJO and ColorEnum objects to illustrate how you can define and populate your beans within Spring XML configuration.

package com.sample.iocbasic;

public class BasicPOJO {

public String name;
public ColorEnum color;
 

public ColorRandomizer colorRandomizer;
// empty constructor

public BasicPOJO() {
}
 

public BasicPOJO(String name, ColorEnum color) {
 this.name = name;
 this.color = color;
}


public String getName() {
 return name;
}


public void setName(String name) {
 this.name = name;
}


public ColorEnum getColor() {
 return color;
}


public void setColor(ColorEnum color) {
 this.color = color;
}


public ColorRandomizer getColorRandomizer() {
 return colorRandomizer;
}


public void setColorRandomizer(ColorRandomizer colorRandomizer) {
 this.colorRandomizer = colorRandomizer;
}


}


package com.sample.iocbasic;
public enum ColorEnum {
  violet, blue, red, green, purple, orange, yellow
}




Constructor Injection

Constructor arguments may be set through XML configuration. This will enable you to inject dependencies through the constructor arguments. 


To do this, use the constructor-arg element within
the bean definition, as shown in next sample.
 

ioc_basics.xml – XML Bean Construction using Parameterized Arguments

<bean id="constructor-setup"
class="
com.sample.iocbasic.BasicPOJO">
  <constructor-arg name=”name” value="red"/>
  <constructor-arg name=”color” value="violet" />
</bean>



Bean References and Setter Injection


Bean properties may be injected into your target beans through references to other beans within the scope of your application context. 


This is known as bean collaboration

This requires defining the additional bean that you wish to refer to, also known as the collaborator. Using the ref attribute in the
property tag enables us to tell Spring which bean we want to collaborate with, and thus have injected
 

ioc_basics.xml – XML Configuration for Bean Collaboration by Setting Injection

<bean id="no-args"
class="
com.sample.iocbasic.BasicPOJO">
  <property name="color" ref="defaultColor"/>
  <property name="name" value="Mario"/>
</bean>


<bean id="defaultColor"
class="
com.sample.iocbasic.ColorEnum"
factory-method="valueOf">
  <constructor-arg value="blue"/>
</bean>

 
Static and Instance Factory Injection
 

Note the factory-method attribute on the defaultColor element. 
In this case the static factory method instantiation mechanism was used

Note also that the class attribute does not specify the type of object returned by a factory method, as it specifies only the type containing that factory method. 

For this simple example, a string was fed to the enum static factory method valueOf, which is the common approach to resolving enum constants from strings. 


When static factory methods are not practical, use instance factory methods instead

These are methods that get invoked from existing beans on the container to provide new bean instances. 
The class in the next sample demonstrates instance factory methods to provide random ColorEnum instances.

ColorRandomizer.java – Class Definition for the ColorRandomizer Factory Bean


package
com.sample.iocbasic;
import java.util.Random;
 

public class ColorRandomizer {
 

 ColorEnum colorException;
 

 public ColorEnum randomColor() {
  ColorEnum[] allColors = ColorEnum.values();
  ColorEnum ret = null;
  do {
   ret = allColors[new Random().nextInt(allColors.length - 1)];
  }
  while (colorException != null && colorException == ret);
  return ret;
 }


public ColorEnum exceptColor(ColorEnum ex) {
 ColorEnum ret = null;
 do {
  ret = randomColor();
 } while (ex != null && ex == ret);
  

 return ret;
}


public void setColorException(ColorEnum colorExceptions) {
 this.colorException = colorExceptions;
}


}

 
To invoke the factory within our Spring context, ColorRandomizer will be defined as a bean, then one of its methods will be invoked in another bean definition as a way to vend an instance of ColorEnum. 


We obtain two separate instances of ColorEnum using both ColorRandomizer factory methods to illustrate variances in factory method invocations.

Obtaining Bean Instances from Factory Methods in Spring
 

<!-- Factory bean for colors -->
<bean id="colorRandomizer" class="
com.sample.iocbasic.ColorRandomizer" />
 

<!-- gets a random color -->
<bean id="randomColor" factory-bean="colorRandomizer" factory-method="randomColor"/>
 

<!-- gets any color, except the random color defined above -->
<bean id="exclusiveColor" factory-bean="colorRandomizer" factory-method="exceptColor">

  <constructor-arg ref="randomColor"/>
</bean>



 
Bean Scopes

Spring uses the notion of bean scopes to determine how beans defined in the IoC container get issued to the application upon request with getBean methods, or through bean references. 


A bean’s scope is set with the scope attribute in the bean element, or by using the @Bean annotation in the class file. 
Spring defaults to the singleton scope, where a single instance of the bean gets shared throughout the entire container. Spring provides a total of six bean scopes out of the box for use in specific context implementations, although only singleton, prototype, and thread are available through all context
implementation. 


The other scopes – request, session, and globalSession – are available only to application contexts that are web-friendly, such as WebApplicationContext.

Bean scopes available in Spring:


Singleton Single bean instance per container, shared throughout the IoC container.


Prototype New bean instance created per request.


Request Web application contexts only: Creates a bean instance per HTTP request.


Session Web application contexts only: Creates a bean instance per HTTP session.


GlobalSession Web portlet only: Creates a bean instance per Global HTTP session.


Thread* Creates a bean instance per thread. Similar to request scope.


* Thread scope is not registered by default, and requires registration with the CustomScopeConfigurer bean.


To illustrate the behavior of prototype- and singleton-scoped beans, next sample declares two beans of the same type, which differ only in scope. 


The value from the singleton-scoped bean should always
return the same value, whereas the prototype-scoped bean will always return different values (since the
factory returns random numbers). 


This shows the Spring configuration file and the next one
shows the main class.


ioc_basics.xml – Overriding Default Scope for Beans with XML Metadata


<beans…>
  <bean id="randomeverytime" factory-bean="colorRandomizer" factory-  method="randomColor"
scope="prototype"/>


  <bean id="alwaysthesame" factory-bean="colorRandomizer factory-method="randomColor"
scope="singleton"/>
 

</beans>

BasicIocMain.java –Simple For-Loop
 

public static void demonstrateScopes(ApplicationContext ctx) {
 for (int i = 0; i < 5; i++) {
  System.out.println("randomeverytime: " +
    ctx.getBean("randomeverytime", ColorEnum.class));
  System.out.println("alwaysthesame: " +
    ctx.getBean("alwaysthesame", ColorEnum.class));
 }
}

 
The output of this loop will emit text similar to this:


Output of Bean Scope Induced Behavior
randomeverytime: green
alwaysthesame: orange
randomeverytime: purple
alwaysthesame: orange
randomeverytime: violet
alwaysthesame: orange
randomeverytime: violet
alwaysthesame: orange
randomeverytime: green
alwaysthesame: orange


You register the thread scope, or any other custom scope, in XML by defining a org.springframework.beans.factory.config.CustomScopeConfigurer bean. 


Pass the scope implementation class to the map property scopes. The map property is evaluated with the key providing the scope name,
and value having the scope’s implementation class. Registering in this fashion is always compatible to @Bean annotated properties with the @Scope annotation. That is, a scope definition once enabled for any given scope is activated throughout the container and for all manners of configuration (see next).


Ioc_basics.xml – Registering Custom Scopes in XML


<beans…>
 <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
 <property name="scopes">
  <map>
   <entry key="thread">
    <bean class="org.springframework.context.support.SimpleThreadScope"/>
   </entry>
  </map>
 </property>
</bean>
<bean id="threadColor" factory-bean="colorRandomizer" factory-method="randomColor"
scope="thread"/>
</beans…>




 

Nessun commento:

Posta un commento