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 replacement 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.
Spring
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) . POJO 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 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 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.