Today, the Principle of Inversion of Control has gained much popularity and Spring is a Light-Weight Framework that adopts this principle extensively for Building Java or J2ee Applications. In most of the times an Application never wants to gain access to all the services provided by the heavy-weight J2ee Container, but still will use it. In such a case, an Application can depend on the light-weight services provided by the Spring Framework/Container. How this is possible is detailed in brief in this article. Anyway Spring is not a complete replacment for J2ee Container. This article provides an Introduction over the Core features of the Spring Framework like how to Declare and Initialize Beans Declaratively, how to establish Dependencies among Beans etc. The later part of the article explores more on the various stuff available within the Bean Xml Configuration File along with plenty of sample snippets. If you want to read more tutorials on Spring, please visit Spring Tutorials.
Spring MVC Tutorial
What is Spring?
also read:
The Core Spring can be thought of a Framework and a Container for managing Business Objects and their relationship. The Beauty of the Framework is that, in most of the times we don’t need to depend on Spring specific Classes and Interfaces. This is unlike other Frameworks, where they will force the Client Applications to depend on their propriety Implementations. For example, consider the various J2ee Components like Servlets or EJB, if a developer wants to write a Servlet, the class has to depend on HttpServlet
, same is the case of creating Enterprise Beans.
The architects of Spring have spent enough time in designing the Framework to keep the coupling between the Clients and the Spring Framework to a bare minimum. In most cases the coupling is often nil. In other terms, whatever Business Components you write in Spring are POJO (Plain Old Java Object) or POJI (Plain Old Java Interface) only. POJO/POJI refers to Classes or Interfaces that doesn’t specially extend of implement third-party Implementations. The main advantage of having most of the Classes or Interfaces as POJO/POJI in an Application is that they will facilitate easy Unit Testing in the Application.
For example, consider the following Non-POJO class,
MyServlet.java
class MyServlet extends HttpServlet{ }
The problem with the above class definition is that it is not a POJO, because it is extending the HttpServlet
class. When this class wants to undergo Unit Testing, someone has to start the Web/Application Server where it is actually deployed to ascertain the functionality of this class, because of the extension of the HttpServlet class which makes sense in the context of a running Server only. Since Spring Framework doesn’t provide tight coupling between the Business Objects, it is fast to do Unit Testing so that TDD (Test Driven Development) can be made easily possible.
Spring Modules
The Spring Project is not a single project but it comes in flavor of Several Modules. A module can be defined or thought of a functionality that is very specific to an area. Spring Distribution comes in several such modules. The name of the Spring module along with the jar file name (which is available in the SPRING_HOME\dist\modules
) is listed below.
- Spring Web MVC (spring-webmvc.jar)
- Spring Aop (spring-aop.jar)
- Spring Beans (spring-beans.jar)
- Spring Context (spring-context.jar)
- Spring Core (spring-core.jar)
- Spring Dao (spring-dao.jar)
- Spring Hibernate (spring-hibernate3.jar)
- Spring Ibatis (spring-ibatis.jar)
- Spring Jca (spring-jca.jar)
- Spring Jdbc (spring-jdbc.jar)
- Spring Jdo (spring-jdo.jar)
- Spring Jms (spring-jms.jar)
- Spring Jms (spring-jpa.jar)
- Spring Jmx (spring-jmx.jar)
- Spring Portlet (spring-portlet.jar)
- Spring Remoting (spring-remoting.jar)
- Spring Struts (spring-struts.jar)
- Spring Support (spring-support.jar)
- Spring Toplink (spring-toplink.jar)
- Spring Web (spring-web.jar)
- Spring Aspects (spring-aspects.jar)
Every module in the above list has their own functionality as identified by the name of the Jar File. For example, Spring Jmx (spring-jmx.jar) provides Instrumentation and Management Support to Spring Bean components. Similarly, Spring Web provides developing Web Application Infrastructure for the Server side. Since all the pieces of functionality are made well modular and they come as a separate functionality (via a Jar File), say, if an Application wants to take functionality of Aspect Oriented programming (spring- aspects.jar) and Database Access (spring-jdbc.jar), it can include any two of these jar Files in its classpath.
But, what will happen if an Application is in need of the functionality provided by all the various modules. Should it define entries for all the Jar Files in its class-path? Spring provides a smart solution for this need, as it comes with a Jar File called spring.jar
which is a combination of all the modules.
Inversion of Control
It is very important to understand the underlying principle of the Spring Framework which is nothing but the Inversion of Control. Let us detail the section of this principle with the help of some sample code. Consider the following sample code containing Java classes.
TaskService.java
public class TaskService{ public Task createTask(){ } public boolean deleteTask(){ } public Set<Task> listTasks(){ } public void update(Task task){ } }
Task.java
class Task{ private TaskService taskService; public Task(TaskService taskService){ this.taskService = taskService; } public void setTaskService(TaskService taskService){ this.taskService = taskService; } public TaskService getTaskService(){ return taskService; } public void update(){ taskService.update(); } }
The above classes represent Task
objects in an Application that represent some work to done by various components. The TaskService
class is a Service Component, meaning that it is used to some other Components, providing functionality for creating (createTask()
), deleting (deleteTask()
) and listing all the Task object (listTasks()
). The original Task model is represented by the Task
class and has some set of methods which are dependent on the TaskService
object.
If Client Applications want to update a Task
object by calling Task.update()
, then the following might have been the code written by them,
TaskClient.java
class TaskClient{ public static void main(String args[]){ TaskService service = new TaskService(); Task task = new Task(service); //Or, task.setTaskService(task); task.update(); } }
Back to Dependency injection, we have two components here namely Task
and TaskService
. Task
is depending on TaskService
Component to get the various functionalities. So there is a dependency association between Task
and TaskService
Component. In our case, the association or the relation between these Components are set by the Client who is using it. Also note that Task
Component is tightly dependent on TaskService
component. If sometimes in the near future, if the requirement changes telling that Task objects should now depend on the TimerService
instead of TaskService
, then will be major change in the Application Code which is generally considered as a poorer Design. So, how to get rid off this?
The Inversion of Control provides a solution for this. The first thing to do is that there should be loose coupling between components. That is all the relationships or association between components should have to be made abstract to the extent possible. It means that the class Task
should not depend on the class TaskService
. Since abstractions in Java are captured in the form of Interfaces or Abstract Classes, one can prefer using any of them. But preferring interfaces for capturing abstractions is highly encouraged. It means that let not the Task
class depends directly on the TaskService
class. Let it define on a Service class, which could be either TaskService
or TimerService
. It means that now we have Class/Interface structures similar to the following,
public interface Service{ } public interface TaskService extends Service{ } public interface TimerService extends Service{ }
And now the code in the Task
class that code that previously referred TaskService
can now be changed something like the following,
Task.java
class Task{ private Service service; public Task(Service service){ this. service = service; } public void setService(Service service){ this. service = service; } public Service getService(){ return service; } }
Now, in the run-time, whether Task
should depend on TaskService
or TimerService
can be easily plugged into with minimal set of changes,
Service service = new TaskService(); // Or, service = new TimerService(); Task task = new Task(service);
The second thing in Inversion of Control is that, never the Client Applications should involve in making associations between the Components through code. Instead, someone called Container or Framework should do these kinds of Component-wiring Activities. Component Wiring is a fancy term given to make associations between various Components. Let us look back into the Application who does the job of Component wiring. Now, Task
is dependent of Service
object and it is the Client code which establishes relations between Task
and the Service
object through the following price of code,
Service service = … Task task = new Task(); task.setService(service);
The Framework insists that Associations between Business objects should be externalized and never the Client Applications should be involved in doing these kinds of activities. Ideally it tells the method setService()
method should be called by the Framework. Here, we see that the Application Control is reversed. Instead of Clients having the control to establish relationship between Components, now the Framework carries this job, which means that the Control is revered from the Clients to the Framework and that’s why this principle is rightly termed as Inversion of Control.
Spring Core API
The Core API in Spring is very limited and it generally involves in Configuring, Creating and Making Associations between various Business Components. Spring refers to these Business Components as Beans. The following are the Core Classes or the Interfaces that are available in the Spring for achieving the goal.
- Resource
- BeanFactory
Let us look into the above entities in brief.
Resource
A Resource
in Spring represents any kind of Information that comes from a File or from a Stream. For example, resources could represent an Xml File containing the various Configuration Information needed for a Spring Application. Or it could represent a Java Class File representing a Bean object. Whatever be the case, it can be represented as a Resource
object with the transparent nature of its implementation.
Suppose, we wish a load a Resource that represents the Java Class called MyJavaClass
, then we can have,
Resource classRes = new ClassPathResource("PathToClassFile", MyJavaClass.class);
Note that ClassPathResource
is the concrete implementation class for loading a Java Class file. The following code loads an Xml File from the local File System.
Resource classRes = new ClassPathResource("PathToClassFile", MyJavaClass.class);
Note that FileSystemResource
can be used to load any kind of files to make themselves available to the Spring Application, it is not restricted to only Xml Files. Other commonly used Resource in the InputStreamResource
that loads content from an Input Stream. Apart from this, there are so many concrete implementations of various Resources are available in the Spring Framework.
BeanFactory
As mentioned, in Spring terminology a Bean refers to a Business Component in consideration. As such, BeanFactory is the factory class for creating Bean objects. The interesting thing is that how to configure the BeanFactory
for creating Business Components. In other words, where the BeanFactory
class should look for the Bean definition for creating Bean instances? One important thing to note that all Beans that reside in the Context of Spring Container are highly configurable through external files. It means that your Bean definitions can reside in an Xml File, a Java Property File or even in a database. Although, Bean definitions are not tightly coupled to any format, most developers prefer having their Bean definitions in Xml Format.
Following is the code that will load all Bean definition from an Xml File,
Resource xmlResource = new FileSystemResource("beans.xml"); BeanFactory factory = new XmlBeanFactory(xmlResource);
Note the XmlBeanFactory
class which is one of the concrete implementations of BeanFactory
class.
Spring MVC Sample Application
It is wise to look into a Sample Application before getting into the other details like the various functionalities and features that can be configured through the Xml File. Let us keep the functionality of the Business Object to a minimal extent.
Business Object
Following is the code for the sample Business Component Namer
which is just used to store the given name.
Namer.java
package net.javabeat.articles.spring.introduction; public class Namer { private String name; public Namer() { } public String getName() { return name; } public void setName(String name) { this.name = name; } }
Note that this class has a single property called 'name'
along with its appropriate getter and setter methods.
Xml Configuration File
Now, let us look into the Xml Configuration File where we are going to define and configure the Bean class along with its properties. Following is the Xml code,
namer.xml
<?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-2.0.xsd"> <bean id = "namerId" class = "net.javabeat.articles.spring.introduction.Namer"> <property name = "name"> <value>Javabeat</value> </property> </bean> </beans>
The very first thing to note that is this Xml follows the standard schema as defined in the url http://www.springframework.org/schema/beans/spring-beans-2.0.xsd. The root element of the Xml file is the 'beans'
element which represents the collection of Business objects to be defined. Every Business Object is identified by the 'bean'
element which has two attributes name 'id'
and 'class'
. The 'id'
attributes should be unique in the Xml File and it can be used in code to refer the Bean class whereas the attribute 'class'
represents the fully qualified class name of the Bean definition. Also note the property element which represents a singe value 'Javabeat'
.
Client Application
Following is the Client code which makes reference to the Xml File using the Resource
object and then the contents of the Xml File (which contains the various Bean definitions) are read using the XmlBeanFactory
class. An instance of the object of type Namer is then retrieved by calling the BeanFactory.getBean(id)
method. Remember that, this id argument value corresponds to the 'id'
attribute of the bean element defined in the Xml File.
SimpleSpringApp.java
package net.javabeat.articles.spring.introduction; import org.springframework.beans.factory.*; import org.springframework.beans.factory.xml.*; import org.springframework.core.io.*; public class SimpleSpringApp { public static void main(String args[]){ Resource namerXmlFile = new FileSystemResource("src/resources/namer.xml"); BeanFactory factory = new XmlBeanFactory(namerXmlFile); Namer namer = (Namer)factory.getBean("namerId"); System.out.println(namer.getName()); } }
Exploring the Bean Definition Configuration File
All the basic definition of the Bean classes along with the Configuration Information, their relationships with other Bean objects can be defined in the Xml Configuration File. The Schema Definition of the Bean Xml Configuration file is very vast in terms of Definitions and Functionalities and the subsequent sections aims in covering only the major configuration features.
Making Associations between Bean Objects
It is a common thing in an Application where we can see so many components interacting within each other thereby full-filling the Client needs. For that, they should Establish Relation-ship between them which can be done easily in the Configuration file. Assume that we have two Components Player
and Team
, whose class structures are given below,
Player.java
public class Player { private String name; private Team team; }
Team.java
public class Team { private String name; }
In the above case we have two Bean Components namely Player
and Team
. Since a Player
is dedicated to one Team
, we have a reference to the Team
object inside the Player
class. Now Team becomes a property for the Player
class. However, it is not a simple property that holds string or integer; instead it is a complex holds whose data-type is of Type Team
.
Following is the sample xml snippet for making association between Player
and Team
objects.
team-player.xml
<bean id = "india" class = "net.javabeat.articles.spring.complex.Team"> <property name = "name"> <value>India</value> </property> </bean> <bean id = "tendulkar" class = "net.javabeat.articles.spring.complex.Player"> <property name = "name"> <value>Sachin Tendulkar</value> </property> <property name = "team"> <ref bean = "india"/> </property> </bean>
Note that the Team
(india) is referenced into the Player
object using the 'ref'
element through the property bean whose value corresponds to the 'id'
attribute of the previously defined Team
object.
Mapping Collection Properties
In this section, let us strengthen the relation-ship between Team
and Player
classes to include various Collection Properties. Following is the class structure of the Team
Class.
Team.java
package net.javabeat.articles.spring.complex; import java.util.*; public class Team { private String name; private Set<Player> players; public Team() { } public Team(String name){ this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Player> getPlayers() { return players; } public void setPlayers(Set<Player> players) { this.players = players; } @Override public String toString(){ return "[Name = " + name + ", Players = " + playersAsString(players) + "]"; } private String playersAsString(Collection<? extends Object> collection){ if(collection == null || collection.isEmpty()){ return ""; } StringBuilder result = new StringBuilder(); Iterator<? extends Object> iterator = collection.iterator(); result.append("["); while (iterator.hasNext()){ String name = ((Player)iterator.next()).getName(); result.append("{" + name + "}"); } result.append("]"); return result.toString(); } }
Since a Team
contains more than one player, we have represented this in programming aspects in the form of Set<Player> players. Let us see later how to map the set of players in the Configuration File. Also note that the toString()
method is overridden to print some meaningful information about the Object. Following is the complete code listing of the Player
Class. Since a player would have played against many teams and have taken runs, a property representing Map
keyed with Team
along with an Integer
(which represents the number of runs scored against a particular Team) is defined.
Player.java
package net.javabeat.articles.spring.complex; import java.util.*; public class Player { private String name; private Team team; private Map<Team, Integer> runsScored; public Player() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public Team getTeam() { return team; } public void setTeam(Team team) { this.team = team; } public Map<Team, Integer> getRunsScored(){ return runsScored; } public void setRunsScored(Map<Team, Integer> runsScored){ this.runsScored = runsScored; } @Override public String toString(){ return "[Name = " + getName() + " , Team Name = " + getTeam().getName() + ", RunsScored = " + runsScoredAsString() + "]"; } private String runsScoredAsString(){ if (runsScored == null || runsScored.isEmpty()){ return ""; } StringBuilder result = new StringBuilder(); result.append("["); Iterator<Map.Entry<Team, Integer>> iterator = runsScored.entrySet().iterator(); while(iterator.hasNext()){ Map.Entry<Team, Integer> entry = iterator.next(); result.append("{" + entry.getKey().getName() + "," + entry.getValue() + "}"); } result.append("]"); return result.toString(); } }
Note that, here also the toString()
method is overridden to print the information from the Map
which contains information about the opposition Team along with the number of runs a player has scored.
player-team.xml
<?xml version="1.0" encoding="UTF-8"?> <beans> <bean id = "india" class = "net.javabeat.articles.spring.complex.Team"> <property name = "name"> <value>India</value> </property> <property name = "players"> <set> <ref bean = "tendulkar"/> <ref bean = "dravid"/> <ref bean = "ganguly"/> </set> </property> </bean> <bean id = "australia" class = "net.javabeat.articles.spring.complex.Team"> <property name = "name"> <value>Australia</value> </property> </bean> <bean id = "south-africa" class = "net.javabeat.articles.spring.complex.Team"> <property name = "name"> <value>South Africa</value> </property> </bean> <bean id = "tendulkar" class = "net.javabeat.articles.spring.complex.Player"> <property name = "name"> <value>Sachin Tendulkar</value> </property> <property name = "team"> <ref bean = "india"/> </property> <property name = "runsScored"> <map> <entry> <key><ref bean = "australia"/></key> <value>5638</value> </entry> <entry> <key><ref bean = "south-africa"/></key> <value>6383</value> </entry> </map> </property> </bean> <bean id = "dravid" class = "net.javabeat.articles.spring.complex.Player"> <property name = "name"> <value>Rahul Dravid</value> </property> <property name = "team"> <ref bean = "india"/> </property> <property name = "runsScored"> <map> <entry> <key><ref bean = "australia"/></key> <value>3638</value> </entry> <entry> <key><ref bean = "south-africa"/></key> <value>3981</value> </entry> </map> </property> </bean> <bean id = "ganguly" class = "net.javabeat.articles.spring.complex.Player"> <property name = "name"> <value>Saurov Ganguly</value> </property> <property name = "team"> <ref bean = "india"/> </property> <property name = "runsScored"> <map> <entry> <key><ref bean = "australia"/></key> <value>4688</value> </entry> <entry> <key><ref bean = "south-africa"/></key> <value>2343</value> </entry> </map> </property> </bean> </beans>
Take a careful look into the Xml File. Since a Team represents a set of players, this information is configured in the Xml File thorough the help of 'set'
element. And since the elements in the set itself are bean objects, they are mentioned using the 'ref'
element. Following is the snippet code for that,
<bean id ="india"> <property name = "players"> <set> <ref bean = "tendulkar"/> <ref bean = "dravid"/> <ref bean = "ganguly"/> </set> </property> </bean>
And coming to the Player object, since the property 'runsScored'
is represented as a Map
whose key is the Team
object valued with the number of runs scored which is an integer, the whole structure is represented using the map element with key and value elements. Following is the xml snippet for the same,
<bean id = "tendulkar" … > <property name = "runsScored"> <map> <entry> <key><ref bean = "australia"/></key> <value>5638</value> </entry> <entry> <key><ref bean = "south-africa"/></key> <value>6383</value> </entry> </map> </bean>
Following is the code snippet of the Client along with the output information, which loads and print values of several of the bean objects
Client Application
Resource resource = new FileSystemResource("./src/resources/player-team.xml"); BeanFactory factory = new XmlBeanFactory(resource); Team india = (Team)factory.getBean("india"); System.out.println(india); Player tendulkar = (Player)factory.getBean("tendulkar"); System.out.println(tendulkar); Player dravid = (Player)factory.getBean("dravid"); System.out.println(dravid); Player ganguly = (Player)factory.getBean("ganguly"); System.out.println(ganguly);
Output of the program
[Name = India, Players = [{Sachin Tendulkar}{Rahul Dravid}{Saurov Ganguly}]] [Name = Sachin Tendulkar , Team Name = India, RunsScored = [{Australia,5638}{South Africa,6383}]] [Name = Rahul Dravid , Team Name = India, RunsScored = [{Australia,3638}{South Africa,3981}]] [Name = Saurov Ganguly , Team Name = India, RunsScored = [{Australia,4688}{South Africa,2343}]]
Importing Configuration Files
Having some much Bean Definition Information in one Configuration File wont look nice especially if the size of the File grows large. Spring provides a modular solution for this problem wherein Bean Definition Objects for one type can be defined in a separate file and the same can be included in the main configuration file. Considering the previous example, we can define all the Player
objects in player.xml
, Team objects in team.xml
and can have a main.xml
file which includes both player.xml
and team.xml
files.
Following is the xml snippet for the same,
main.xml
<?xml version="1.0" encoding="UTF-8"?> <beans> <import resource = "player.xml"/> <import resource = "team.xml"/> </beans>
Bean Lifecyle
The entire Bean objects defined in the Xml Configuration File undergoes a Standard Lifecycle Mechanism. Lifecycle interfaces like InitializingBean and DisposableBean are available. Care should be taken while using these Interfaces. Since these are Spring specific Interfaces, your application code will tightly be Coupled with the Spring Implementation. So define and use these interfaces when there is really a need.
The InitializingBean
interface has a single method called afterPropertiesSet()
which will called immediately after all the property values that have been defined in the Xml Configuration file is set. Any customized initiation logic or mandatory checking can be done here. Similarly, the DisposableBean
has a single method called destroy()
which will be called during the shut down of the Bean Container.
Following is the code snippet illustrating the usage of these interfaces,
Employee.java
package net.javabeat.articles.spring.complex; import org.springframework.beans.factory.*; public class Employee implements InitializingBean, DisposableBean{ private String name; private String id; public void afterPropertiesSet() throws Exception { System.out.println("Employee->afterPropertiesSet() method called"); } public void destroy() throws Exception { System.out.println("Employee->destroy() method called"); } }
Controlling the Order of Creation of Beans
Sometimes we may end up in a situation that Component A must be created before Component B. In such a case we can use the depends-on
attribute which takes a list of previously defined Bean Definition identifiers. For example, consider that we have three Bean Classes namely Employee
, Department
and Organization
. And the situation is that we want the Creation of Bean objects to be followed in this order, Organization
followed by Department
and then Employee
.
Following is the Xml snippet code that achieves the same,
<bean id = "joseph" class = "net.javabeat.articles.spring.complex.Employee" depends-on = "admin"> </bean> <bean id = "admin" class = "net.javabeat.articles.spring.complex.Department" depends-on = "oracle"> </bean> <bean id = "oracle" class = "net.javabeat.articles.spring.complex.Organisation"> </bean>
Creating Bean Instances through Factory classes
Suppose say that we already have a Factory class for creating a Bean object and we want to make use of this factory class. Then the usage of 'factory-method'
and 'factory-bean'
attributes will come into picture. Let us have the following sample code to make things clearer.
Team.java
public class Team{ private String name; }
TeamFactory.java
public class TeamFactory { public static Team getTeamUsingStaticMethod(){ System.out.println("Static Method Called"); return new Team(); } public Team getTeamNormalMethod(){ System.out.println("Instance Method Called"); return new Team(); } }
The above Factory class has two methods that will return Team
objects. One is the static factory method and the other one is the regular instance method. If we want make use of the static method TeamFactory.getTeamUsingStaticMethod()
, then we should change the bean definition in the Configuration File to something like the following,
<bean id = "india" class = "net.javabeat.articles.spring.complex.TeamFactory" factory-method = "getCountryUsingStaticMethod"> <property name = "name"> <value>India</value> </property> </bean>
In the above case, the class attribute must point to the name of the Factory class and the factory-method
attribute must be the name of the static method which will return the instance. And as usual, the property element is used to pass values to the Team object while creating the instance.
If instead, we want to make use of the normal instance method, i.e. TeamFactory.getTeamNormalMethod()
, then we should define the factory class itself as a bean and then have to make references to the instance method in the Bean definition. Consider the following changes in the Xml File,
<bean id = "teamFactoryId" class = "net.javabeat.articles.spring.complex.TeamFactory"> </bean> <bean id = "australia" factory-bean = "teamFactoryId" factory-method = "getCountryUsingNormalMethod"> <property name = "name"> <value>Australia</value> </property> </bean>
The first thing to note is a Bean definition is made for the Factory class TeamFactory
and then in the definition of the bean itself, the 'factory-bean'
attribute points to the identifier that was previously defined with the factory-method
attribute pointing to the name of the instance method that will create Team objects.
Bean Inheritance
Minimal support of Inheritance is given between the Bean Components in the form of the attribute 'parent'
within the 'bean'
tag. For example, consider the following classes Planet
and Earth
. The Class Planet has two properties namely 'name'
and 'shape'
. The values for these properties might be ‘Planet’ and ‘Elliptical’. The other class Earth
(which is a Planet too) extends the Planet
class, but we wish that for the Class Earth the property values should be ‘Earth’ and ‘Elliptical’.
So, we are doing two things here. One is, the class Earth
is extending from the class Planet
. And the other thing is the values for the Planet
object (‘Planet, ‘Elliptical’) is overridden for the Earth
object with values (‘Earth’ and ‘Elliptical’). Following is the code snippet for the classes Planet
and Earth
.
Planet.java
public class Planet { private String name; private String shape; }
Earth.java
public class Earth extends Planet { }
And the changes in the Xml Configuration File are the inclusion of the attribute 'parent'
in the bean definition for the Earth
object. Also note that since we want the value ‘Earth’ for the name property we have overridden the value just by redefining it.
planet-earth.xml
<bean id = "planet" class = "net.javabeat.articles.spring.complex.Planet"> <property name = "name"> <value>Planet</value> </property> <property name = "shape"> <value>elliptical</value> </property> </bean> <bean id = "earth" class = "net.javabeat.articles.spring.complex.Planet" parent = "planet"> <!-- Name property value overriden here --> <property name = "name"> <value>Earth</value> </property> </bean>
Here is the code snippet of the Client Application,
Client Application
Resource resource = new FileSystemResource("./src/resources/planet-earth.xml"); BeanFactory factory = new XmlBeanFactory(resource); Planet planet = (Planet)factory.getBean("planet"); System.out.println(planet); Planet earth = (Planet)factory.getBean("earth"); System.out.println(earth);
also read:
Conclusion
Even though there are lots and lots of functionality in the Spring Core, this article attempted to cover only the basic things. More specifically it concentrated on the various Spring Modules that are resting on top of the Spring Core Framework. Then a good treatment along with some samples is given in the topic Inversion of Control and how well this principle fits into the Spring Architecture is discussed.
Then the remaining part of the article explored much about the usage of the various Configuration Stuffs available in the Xml Configuration File. More specifically, Creation of Bean Objects, Mapping between Bean Objects, Collection Mapping, Instantiation through Factory Class, Bean Inheritance, Bean Lifecycle, Configuration Files Import, Controlling the Bean Creation Order is given good coverage.