Chapter 2. Fundamentals

We saw the bare-minimum basics of Spring Framework in the last chapter. We worked with new things such as beans, bean factories, and containers. This chapter explains them in detail. It discusses writing beans, naming conventions, how they are wired into containers, and so on.

Configuring Beans

For Spring, all objects are beans! The fundamental step in the Spring Framework is to define your objects as beans. Beans are nothing but object instances that would be created and manage by the Spring Framework by looking at their class definitions. These definitions basically form the configuration metadata. The framework then creates a plan for which objects need to be instantiated, which dependencies need to be set and injected, and the scope of the newly created instance, etc., is based on this configuration metadata.

The metadata can be supplied in a simple XML file, as we saw in Chapter 1. Alternatively, one could provide the metadata as annotation or Java Configuration.

We first discover the definitions of the Spring beans by using a config file which is discussed in the next section.

Using XML

We saw earlier that the Framework reads the Java classes defined in the XML config and initializes and loads them as Spring beans into a runtime container. The container is a runtime bucket of all the fully prepared instances of Java classes. Let’s take a look at an example of how this process is executed.

We will define a bean with a name person that corresponds to a class Person. The Person has three properties, two of which ( firstName and lastName) were set via the constructor, while the third one ( age) is set by using a setter. There is also another property called address. However, this property is not an simple Java type, but instead points (references) to another class Address.

The following snippet shows the Person bean class’s definition:

public class Person {
  private int age = 0;
  private String firstName = null;
  private String lastName = null;
  private Address address = null;

  public Person(String fName, String lName){
    firstName = fName;
    lastName = lName;
  }
  public int getAge() {
    return age;
  }
  
  public void setAge(int age) {
    this.age = age;
  }
  public Address getAddress() {
    return address;
  }
  public void setAddress(Address address) {
    this.address = address;
  }
  public String getDetails(){
    return firstName +" "+lastName 
      +" is "+getAge()+" old and lives at "+getAddress();
  }
}            

As you can see, only age and address variables have setters—meaning they are set in a different way than the variables set via constructor. For completeness, the Address class definition is:

public class Address {
  private int doorNumber = 0;
  private String firstLine = null;
  private String secondLine = null;
  private String zipCode = null;
  // getters and setters for these variables go here
  ....
}            

The ultimate goal is to create the Person and Address beans via our configuration files. The classes are declared in a Spring configuration XML file as shown here:

<?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.xsd">

  <bean name="person" class="com.madhusudhan.jscore.beans.Person">
    <constructor-arg value="Madhusudhan" />
    <constructor-arg value="Konda" />
    <property name="age" value="99"/>
    <property name="address" ref="address"/>
  </bean>
    
  <bean name="address" class="com.madhusudhan.jscore.beans.Address">
    <property name="doorNumber" value="99"/>
    <property name="firstLine" value="Rainbow Vistas"/>
    <property name="secondLine" value="Kukatpally, Hyderabad"/>
    <property name="zipCode" value="101010"/>
  </bean>
</beans>

There are few things that we should take a note of here.

The topmost node declares <beans> as your root element. All bean definitions would then follow using a <bean> tag. Usually, the XML file consists of at least one bean. Each bean definition may contain sets of information, most importantly the name and the class tags. It may also have other information, such as the id, the scope of the bean, the dependencies, and others.

Basically, when the config file is loaded at runtime, the framework will pick up these definitions and create the instance of Person. It then gives a name as person. This name is then used to query for the same instance from the container by using a Framework’s API.

For example, the following code snippet illustrates how a PersonClient loads up its container and queries the beans:

public class PersonClient {
  private static ApplicationContext context = null;
  public PersonClient() {
    context = new ClassPathXmlApplicationContext("ch2-spring-beans.xml");
  }
  public String getPersonDetails() {
    Person person = 
     (Person) context.getBean("person");
     return person.getDetails();
  }
}               

From the above snippet, two steps are significant.

  • The ApplicationContext is instantiated by an appropriate beans config file. This context is nothing but our bucket of beans—a container in Spring’s terminology.

  • Querying the container for our newly created Person bean. We use the framework’s Context API to search the Java instance, using the getBean() method. The string value that you pass to this getBean() query API method is the name that you’ve given the bean in your XML file—person in this case.

You can split the bean definitions across multiple files.

For example, you create all the beans that deliver the business functions in a file called business-beans.xml, the utility beans in util-beans.xml, data access beans in dao-beans.xml, and so on. We will see how to instantiate the Spring container by using multiple files later in the chapter.

Generally, I follow the convention of creating the files by using two parts separated by a hyphen. The first part usually represents the business function, while the second part simply indicates that these are spring beans. There is no restriction on the naming convention, so feel free to name your beans whatever you like.

Each bean should either have a name or id field attached to it. You can create the beans with neither of these things, making them anonymous beans (which are not available to query in your client code). The name and id fields both serve the same purpose, except that the id field corresponds to XML specification’s id notation. This means that checks are imposed on the id (for example, no special characters in the id value). The name field does not attract any of these restrictions.

The class field declares the fully qualified name of the class. If the instantiation of the class requires any initialization data, it is set via properties or a constructor argument.

For example, in the above XML file, the Person object is instantiated with both: a constructor argument and property setters. The firstName and lastName were set using the <constructor-arg value="..."/> tag, while the rest of the properties were set using a simple property tag: <property name="age" value=".."/>.

The value fields can be simple values or references to other beans. A ref tag is used if a the bean needs another bean, as is seen for address: <property name="address" ref="address"/> . Note the use of ref keyword rather than value keyword when another bean is referenced.

You can name the bean as you wish. However, I would suggest sticking to a camelCase class name, with the first letter lowercase.

Using Annotations

One possible way of Spring wiring is using annotations. When you choose to go along the path of annotations to define your beans and wire them, you are effectively reducing your XML meta data configurations.

Let’s see how we can define beans using annotations. The ReservationManager has one dependency—a ReservationService. The sevice property must be injected into our manager to do its flight reservation work.

The dummy service definition is shown here:

public class ReservationService {
    public void doReserve(ReservationMessage msg){
        //
    }
}

The ResevationManager has a dependency—it needs the reservation service so it process the flight reservations. In order to fulfil this dependency, we need to inject the service into the manager. Unlike the config route, we will inject this dependency by using an annotation called @Autowired annotation. See how we decorated the variable reservationService, using this annotation shown in the following snippet:

public class ReservationManager {
  @Autowired
  private ReservationService reservationService = null;
  
  public void process(Reservation r) {
    reservationService.reserve(r);
  }
}

When a variable, method or constructor is annotated with @Autowired, framework will find the relevant dependency and inject that dependency automatically. In the preceding case, the ReservationManager is looking for a ReservationService instance. Behind the scenes, the framework will wire the bean by finding it byType (check the autowiring section for more details).

One last thing we need to do is let framework know we are going to use annotations. The way we do this is to declare a special tag in the XML file:

<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:annotation-config/>
  <!-- our reservation service -->
  <bean name="resSvcABC" 
    class="com.madhusudhan.jscore.fundamentals.annotations.ReservationService"/>
  <bean name="reservationManager" 
    class="com.madhusudhan.jscore.fundamentals.annotations.ReservationManager"/>
</beans>

The annotation-config tag lets the framework know we are following the annotations route. This way, it starts searching for the classes that may have the appropriate annotations (in our case, we have ReservationManager with @Autowired annotation) and do fulfil any obligations.

Note that we need to import appropriate context schemas as shown in bold in the above snippet.

When ReservationManger gets created, the framework looks for a ReservationService type bean (we have created one in the bean config) and injects it. I have deliberately set the name of the service bean to resSvsABC so you would know that framework uses byType rather than byName when picking up the dependencies.

When the reservationManager gets created, it will always be injected with the service bean!

There are couple of things that we should look at.

We did not declare any properties on the ReservationManager, for example, <property name="reservationService" ref="resSvs"/>, as we would do normally. There are no setters and getters on the ReservationManager too. This is all redundant because the job is cleanly done by the annotation configuration!

Before we close this section, there’s another attribute that we should see—the component-scan attribute on the context namespace.

In the previous snippet, although we have eliminated much of XML, we still had to define the service bean in the XML. Is there a way we could avoid this and condense our XML further?

Yes, we should use the component-scan attribute that gobbles away much of our XML. As the tag may indicate, component-scan basicaly scans a particular drectory or directories to find out special annotated classes.

Revisiting the ReservationService, annotate the class by using the @Component annotation:

@Component
public class ReservationService {
  ..   
}       

Any class annotated with this @Component annotation will be picked up by the framework (as long as the class is the part of the component-scan’s base-package value) and gets instantiated. The next thing we need to do is to declare the component-scan as shown here:

<context:component-scan 
  base-package="com.madhusudhan.jscore.fundamentals.annotations"/>

By declaring this tag, what we are telling the framework is to search all the annotated (with @Component) classes in the package indicated by base-package attribute. Hence ReservationService will be searched for and instantiated by the framework and gets injected into the ReservationManager bean because of @Autowired annotation.

If you do not wish to tie up to Spring’s @Autowired annotation usage, perhaps think about using JSR-330’s @Inject annotation. Spring supports this annotation too. Although we can’t discuss @Inject annotation here, it is almost replica of @Autowired annotation.

There’s a lot of debate on using annotations against XML configurations. Although annotations do not clutter our XML files, they are tied to the source. There are various schools of thought, some encouraging while others are discouraging the use of annotations. Personally, I like annotations and their clean and neat approach to solving configuration issues. However, I prefer to use meta-data for the simple reason that I can change the configuration without having to recompile/rebuild the application.

XML Namespaces

Sometimes the configuration files seems to have lot of bean information. This is an eyesore to readers at times. However, the good news is that they can be condensed by using schema-based XML configuration. We have been using XML Schemas all along in as the following meta data snippet illustrates:

<?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">
  <!-- declare your beans here -->
  <bean>
                ...
  </bean>
</beans>
            

As you can see, the beans schema has been used in the above configuration. Spring defines various schemas such as jms, aop, jee, tx, lang, util, and others.

Adding the appropriate schemas is quite straightforward. For example, if you are going to use a jms schema, add the following lines (in bold) to the configuration:

<?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:jms="http://www.springframework.org/schema/jms"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/jms
       http://www.springframework.org/schema/jms/spring-jms-3.0.xsd">
       ....
</beans>
            

A xmlns tag defines a jms namespace while the last two line indicate the location of the schema definitions. So, replace the xxx shown in the following pattern with a specific schema you wish to import:

<!-- Replace xxx with one of the many schemas such as jms, aop, tx etc -->
        http://www.springframework.org/schema/xxx
http://www.springframework.org/schema/xxx/spring-xxx-3.0.xsd

Once you have the appropriate schema and the associated namespace (using the xmlns tag), using the schema-based configuration is a breeze.

<?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:jms="http://www.springframework.org/schema/jms"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/jms
       http://www.springframework.org/schema/jms/spring-jms-3.0.xsd">
       
       <jms:listener-container>
         ...
       </jms:listener-contaner>
</beans>
            

See how the listener-container bean is added to the container by using the jms namespace.

The good old DTD-style configuration is still valid too:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
          "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
  ....
</beans>

However, I strongly recommend using the schema-based configuration unless you have a valid reason to stick to older DTD style.

Creating Beans

The beans are instances wired together to achieve an application’s goal.

Usually in a standard Java application, we follow a specific life cycle of the components, including their dependencies and associations.

For example, when you start a main class, it automatically creates all the dependencies, sets the properties, and instantiates the dependent instances for your application to progress.

The responsibility of creating the dependency and associating this dependency to the appropriate instance is given to your main class in our standalone application.

However, in Spring, this responsibility is taken away from us and given to the Spring Framework. The instances (a.k.a. beans) are created, the associations are established, and dependencies are injected by the Spring Framework entirely. You and I have no say except in defining and loading them.

So, creating the whole object graph is the responsibility of the framework!

These beans that exists in a container are then queried by the application and act upon them. Of course, you would have to declare these associations and other configuration metadata either in an XML file or provide them as annotations for the Framework to understand what it should do.

One important characteristic of the Framework while creating beans is to follow a fail-fast approach.

When the Framework encounters any issues in loading a bean, it just quits—no container with half-baked beans ever gets created. This is a really good characteristic of a framework as it would be forced to catch all errors during compile time rathen than at runtime.

Life Cycle

The Spring Framework does quite a few things behind the scenes.

The life cycle of a bean is easy to understand, yet different from the life cycle exposed in a standard Java application. In a normal Java process, a bean is usually instantiated using a new operator. The Framework executes more actions in addition to simply creating the beans. Once they are created, they are loaded into the appropriate container (we will learn about containers in Chapter 3) for a client to access them.

The usual life-cycle steps are listed here:

  • The framework factory loads a bean definitions and creates it.

  • The bean is then populated with the properties as declared in the bean definitions. If the property is a reference to another bean, the other bean will be created and populated, and the reference is injected into this bean.

  • If our bean implements any of the Spring’s interfaces, such as BeanNameAware or BeanFactoryAware, appropriate callback methods will be invoked.

  • The framework also invokes any BeanPostProcessor’s associated with your bean for pre-initialzation.

  • The init-method, if specified, is invoked on the bean.

  • The post-initialization will be performed if specified on the bean.

Do not get stressed if the things mentioned here don’t get digested yet—we will discuss these points in the coming sections in detail.

When comes to creating the beans, beans which have no dependencies will be created normally. Whereas, the beans which has dependencies (that is, some of its properties refer to other beans) will be created only after satisfying the dependencies they have.

We will discuss this process in the next section, using some examples.

Note that we can also create beans by using static methods or Factories. We will look at them in the next chapter in detail.

Instantiating Beans Without Dependencies

Do you remember the FileReader class we defined in our earlier chapter? Here’s the snippet of the class if you can’t recall:

public class FileReader implements IReader{
  private StringBuilder builder = null;
  private Scanner scanner = null;

  // constructor
  public FileReader(String fileName) { ... }

  // read method implementation
  public String read() { ... }
}
            

The FileReader’s constructor takes in a fileName as its argument in order to get ready for the action. This bean is defined by passing an argument to the constructor, using meta-data. Look at the meta data of the bean:

<bean name="reader" class="com.madhusudhan.jscore.basics.readers.FileReader">
  <constructor-arg value="src/main/resources/basics/basics-trades-data.txt" />
</bean>     

The required fileName variable is set with a value via the constructor-arg tag, providing a value of src/main/resources/basics/basics-trades-data.txt as an argument.

When the Framework reads the definition of this class, it creates an instance by using the new operator (in reality, the bean is instantiated by using Java Reflection). As this bean has no dependencies, it will now be instantiated and ready to use.

Instantiating Beans With Dependencies

There is a second case where beans depend on other beans. For example, we have seen a Person having an Address. Unless the Address object is created, creating the Person can’t be succesful. So, the Person bean is dependent on the Address bean. However, if the FileReader bean has a dependency on another bean, the other bean will be created and instantiated. See the following snippet.

See the definition of Person having an address property which refers to another bean named address? The Person object will be injected with an Address object to satisfy the dependency. The bean dependencies can be one or more beans.

<bean name="person"
  class="com.madhusudhan.jscore.beans.Person">
  ....
  <property name="address" ref="address"/>
</bean>
    
<bean name="address" 
  class="com.madhusudhan.jscore.beans.Address">
  ....
</bean>
            

The order of creation is important to Spring. After digesting the configuration metadata, Spring creates a plan (it allocates certain priorities to each bean) with the order of beans that needs to be created to satisfy dependencies. Hence, the Address object is created first, before the Person. If Spring encounters any exception while creating the Address object, it will fail fast and quit the program. It does not create any further beans and lets the developer know why it won’t progress further.

Aliasing Beans

Sometimes, we may need to give the same bean a different name—usually as alias. For example, an Address bean can be called as shipping address or a billing address. Aliasing is a way of naming the same bean with different names. We use the alias tag to give a name to a predefined bean.

<bean name="address" 
  class="com.madhusudhan.jscore.fundamentals.Address">
  ...       
</bean>

<alias name="address" alias="billingAddress"/>
<alias name="address" alias="shippingAddress"/>    

In the above snippet, we have declared an Address bean with address as it’s name. Two aliases, billingAddress and shippingAddress were declared, both pointing to the same bean. We can use either of the aliases in our application as if they were original beans.

Anonymous Beans

We can also create beans whose existence is associated to the referencing bean only. These types of beans are called Anonymous or Inner beans. They are nameless and hence not available for our programs to query them.

<bean name="reader" class="com.madhusudhan.jscore.basics.readers.FileReader">
  <constructor-arg value="src/main/resources/basics/basics-trades-data.txt" />
  <property name="platformLineEnder" 
    <bean class="com.madhusudhan.jscore.basics.readers.WindowsLineEnder"/>
  </property>
</bean>
            

The platformLineEnder property refers to a WindowsLineEnder bean. Because the platformLineEnder bean has been defined as a property (no ref tag is defined), it is not available to any other beans in the context except the FileReader bean.

Injection Types

Spring allows us to inject the properties via constructors or setters. While both types are equally valid and simple, it’s a matter of personal preference in choosing one over the other.

One advantage to using constructor types over setters is that we do not have to write additional setter code. Having said that, it is not ideal to create constructors with lots of properties as arguments. I detest writing a class with a constructor that has more than a couple of arguments!

Constructor Type Injection

In the previous examples, we have seen how to inject the properties via constructors by using the constructor-arg attribute. Those snippets illustrate the constructor injection method. The basic idea is that the class will have a constructor that takes the arguments, and these arguments are wired via the config file.

Here is an FtpReader code snippet that has a constructor taking two arguments:

public class FtpReader implements IReader {
  private String ftpHost = null;
  private int ftpPort = 0;

  public FtpReader(String ftpHost, int ftpPort) {
    this.ftpHost = ftpHost;
    this.ftpPort = ftpPort;
  }

  @Override
  public String read() {
    // your impl goes here
    return null;
  }
}
                

The ftpHost and ftpPort arguments are then wired using constructor-arg attributes defined in the XML config file:

<bean name="reader" class="com.madhusudhan.jscore.basics.readers.FtpReader">
  <constructor-arg value="madhusudhan.com" />
  <constructor-arg value="10009" />
</bean>        

You can set references to other beans, too via the constructor arguments. For example, the following snippet injects a reference FileReader into the ReaderService constructor:

<bean name="readerService" 
    class="com.madhusudhan.jscore.basics.service.ReaderService">
  <constructor-arg ref="reader" />
</bean>

<bean name="reader" class="com.madhusudhan.jscore.basics.readers.FileReader">
  <constructor-arg value="src/main/resources/basics/basics-trades-data.txt" />
</bean>

This is how the ReaderService will look with a constructor accepting an IReader type:

public class ReaderService {
  private IReader reader = null;

  public ReaderService(IReader reader) {
    this.reader = reader;
  }
  ...
}

Argument type resolution

One quick note about constructor type injection—there are couple of rules that framework will follow when resolving the types of the arguments. In the preceding FtpReader example, the first argument was ftpHost followed by ftpPort. The case is straightforward—the constructor expects a string and an integer, so the framework picks the first argument as String type and the second one as Integer type.

Although you declare them as string values in your config file (such as value=".."), the java.beans.PropertyEditor’s are used by the framework to convert the string value to the appropriate property type.

Ideally, the declaration should define the types too as shown in the following snippet:

<bean name="reader" class="com.madhusudhan.jscore.basics.readers.FtpReader">
  <constructor-arg type="String" value="madhusudhan.com" />
  <constructor-arg type="int" value="10009" />
</bean>
                

The types are normal Java types—such as int, boolean, double, String, and so on.

You could also set index’s on the values, starting the index from zero as shown here:

<bean name="reader" class="com.madhusudhan.jscore.basics.readers.FtpReader">
  <constructor-arg index="0" type="String" value="madhusudhan.com" />
  <constructor-arg index="1" type="int" value="10009" />
</bean>

Setter Type Injection

In addition to injecting the dependent beans and properties via constructors, Spring also allows them to be injected via setters, too. In order to use the setter injection, we have to provide setters on the respective variables. If the property exhibits read and write characteristics, provide both a setter and a getter on the variable.

So, in our ReaderService class, create a variable of IReader type and a matching setter/getter for that property. The constructor is left empty as the properties are now populated using the setters. You should follow the normal bean conventions when creating setters and getters.

Modified ReaderService is given here:

public class ReaderService {
  private IReader reader = null;

  // Setter and getter
  public void setReader(IReader reader) {
    this.reader = reader;
  }
  
  public IReader getReader() {
    return reader;
  }
  ...
}            

The significant points are the the setter and getter methods on the IReader variable and the omission of the constructor altogether. The configuration of the class in our XML file looks like this:

<bean name="readerService" 
    class="com.madhusudhan.jscore.basics.service.ReaderService">
  <!-- Setter type injection -->
  <property name="reader" ref="reader"/>
</bean>

<bean name="reader" class="com.madhusudhan.jscore.basics.readers.FileReader">
  ...
</bean>
            

The notable change is to create a property called reader and set it with a reference to the FileReader class. The framework will check the ReaderService for a reader property and invoke setReader by passing the FileReader instance.

Mixing Constructor and Setter

You can mix and match the injection types as you like, too. The revised FileReader class listed here has a constructor as well as few other properties. The componentName is set using setter, while the fileName is injected via constuctor.

<bean name="reader" 
    class="com.madhusudhan.jscore.fundamentals.injection.FileReader">
  <constructor-arg value="src/main/resources/basics/basics-trades-data.txt" />
  <property name="componentName" value="TradeFileReader"/>
</bean>                

Although mixing and matching the injection types is absolutely possible, I recommend sticking with one or the other of them, rather than both, to avoid complicating matters.

Bean Callbacks

Spring Framework provides a couple of hooks to our beans in the form of callback methods. These methods provide opportunity for the bean to initialize properties or clean up resources. There are two such method hooks: init-method and destroy-method.

init-method

When a bean is being created, we can let Spring invoke a specific method on our bean to initialize. This method provides a chance for the bean to do housekeeping stuff and any initialization, such as creating data structures, creating thread pools, and so on.

Say we have a requirement of creating a class for fetching Foreign Exchange (FX) rates. The FxRateProvider is a class that provides us with these rates when queried (mind you, it’s a dummy implementation of FX Rates!).

See the code snippet here:

public class FxRateProvider {
  private double rate = 0.0;
  private String baseCurrency = "USD";
  private Map<String, Double> currencies = null;

  /* Invoked via Spring's init-method callback */
  public void initMe(){
    currencies = new HashMap<String, Double>();
    currencies.put("GBP",1.5);
    currencies.put("USD",1.0);
    currencies.put("JPY", 1000.0);
    currencies.put("EUR",1.4);
    currencies.put("INR",50.00);
  }

  public double getRate(String currency){
   if(!currencies.containsKey(currency))
     return 0;
   return currencies.get(currency);
  }
}

A noticeable point is the initMe method. It is a normal method invoked by the Framework during the process of its creation.

The associated configuration of the bean is provided in the following XML:

<bean name="fxRateProvider" 
  class="com.madhusudhan.jscore.fundamentals.callbacks.FxRateProvider" 
  init-method="initMe">
  <property name="baseCurrency" value="USD"/>
</bean>

destroy-method

Similar to the initialization, framework provides a destroy method to clean up before destroying the bean—named as destroy-method. The FxRateProvider shown here has a destroy method:

public class FxRateProvider {
  
  public void destroyMe() {
    // do your cleanup operations here
    currencies = null;
  }
...
}

We should refer the destroyMe method in the XML declaration like this:

<bean name="fxRateProvider" 
  class="com.madhusudhan.jscore.fundamentals.callbacks.FxRateProvider" 
  init-method="initMe" 
  destroy-method="destroyMe">
  
  <property name="baseCurrency" value="USD"/>
</bean>

When the program quits, the framework destroys the beans. During the process of destruction, when the config metadata declares destroyMe as the destroy method, the destroyMe method is invoked. This gives the bean a chance to do some housekeeping activities if we wish.

Ideally, this method should be coded to free up resources, nullify objects, and other cleanup operations.

Common Callbacks

Let’s say we religiously code a init and destroy methods on all our beans. Does it mean we have to declare the init-method and destroy-method explicitly on each and every bean? Well, not exactly.

As long as we define the same method names across all the beans, we can use Framework’s facility of declaring default callbacks—default-init-method and default-destroy-method.

Instead of declaring the individual methods on each of the bean, we need to declare these default callbacks at the topmost beans element. See how they have been declared in the following XML snippet:

<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" 
       default-init-method="initMe"
       default-destroy-method="destroyMe" >
  <bean>
  ...
  </bean>
</beans>

Note that these default methods are associated to the beans element rather than a bean element.

From the above example, the initMe and destroyMe methods will be invoked automaticaly on all the beans. If any of the beans don’t have these methods, Framework ignores them and no action is performed.

Summary

This chapter discussed the Spring Framework in detail. It explained the concept of beans and bean factories. We have also learned about the life cycle of the bean scopes and touched upon the property editors used in injecting Java Collections and other types of objects.

We discuss the containers and application contexts in the next chapter, which forms a crucial concept in putting the framework to work.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.15.42.128