Language Translator

Showing posts with label Spring. Show all posts
Showing posts with label Spring. Show all posts

Spring Dependency Injection and IOC


DI is a technique to make the code loosely coupled and classes independent by injecting the dependencies externally rather than creating or finding the dependency within the class. So, that we can reuse the code/classes independently.

DI inturn also being called as inversion of control (IOC) also, because the responsibility of deciding and injecting the dependency is not dependent on the class rather it is injected by container at runtime.

In Spring dependencies to a class can be injected in two main ways:
a) Setter Injection : When the dependencies are injecting through setters, we called them as setter injection
b) Constructor injection: When the dependencies inject through the constructors we called them as constructor injection.

I would like and try to clear this by an example (using setter injection):

Suppose,

a) I have a class (DAO class) name "MyDAO" implementing interface DAO, having some database accesslogic in it. for example: some read, insert and delete functions.

interface DAO{

  public boolean insertObject(Object obj);
  public Object readObject(int objId);
  public boolean deleteObject(Object obj);

}

class MyDAO implements DAO {

  private DBConnection connection;

  public boolean insertObject(Object obj){
return connection.getConnection().performInsert(obj);

   }

  public Object readObject(int objId){
return connection.getConnection().readObj(objId);

   }

  public boolean deleteObject(Object obj){
return connection.getConnection().deleteObj(objId);
   }

  public DBConnection getDBConnection(){
return this.connection;
   }

  //setter injection
  public void setDBConnection(DBConnection con){    
this.connection = con;
   }

}

b) Similarly, have three classes specific to the type of database connection, implementing same interface name as "DBConnection".

interface DBConnection{
  public Connection getConnection();
}

class OracleConnection implements DBConnection{
  public Connection getConnection(){...}

}

class DB2Connection implements DBConnection{
 public Connection getConnection(){...}

}

class MySQLConnection implements DBConnection{
 public Connection getConnection(){...}
}


c) **If you have noticed, the reference of this same interface we have given above in the "MyDAO" class, this is the point where injection will occur.

The setter injection of any of the above database connection can be done to "MyDAO" class can be done by even standard java, with the help of helper classes. But, as we are using Spring, we will use dependency injection (declarative injection using xml file) provided by Spring container.

So, create a Spring bean configuration file name as "Spring-Config.xml" and declare all the dependencies in it.

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

<bean id="myDao" class="MyDAO">
<property name="dbConnection" ref="oracleDBConnection" /> //Setter injection
</bean>

<bean id="oracleDBConnection" class="OracleConnection " />
<bean id="db2DBConnection" class="DB2Connection" />
<bean id="mysqlDBConnection" class="MySQLConnection" />

</beans>

d) If you observed by above, we can refer/inject any of the database connection (oracle, db2, mysql) to "MyDAO" class with very little change in spring configuration file "Spring-Config.xml".


e) We can call the MyDAO class in our application,lets take class having java main method

class Main{
public static void main (String arr[]){

int objId=1;

ApplicationContext context =
      new ClassPathXmlApplicationContext(new String[] {"Spring-Cinfig.xml"});

    DAO dao = (DAO)context.getBean("myDao");
Object obj = dao.readObject(objId);

}
}

If you have observed all the way down till now,
a) I have made MyDAO class loosely coupled and can use any type database connection with very very minor change in the XML file.
b) This will help in easy testing of MyDao class logic using connection mockobjects for unit testing.
c) This makes my project very flexible, scalable and maintainable. This point is vital in case of large enterprise java projects.

Spring Work Flow and Its Controllers Behaviour

WORKFLOW
After a DispatcherServlet has received a request and has done its work to resolve locales, themes and suchlike, it then tries to resolve a Controller, using a HandlerMapping. When a Controller has been found to handle the request, the handleRequest method of the located Controller will be invoked; the located Controller is then responsible for handling the actual request and - if applicable - returning an appropriate ModelAndView. So actually, this method is the main entrypoint for the DispatcherServlet which delegates requests to controllers. This method - and also this interface - should preferrably not be implemented by custom controllers directly, since abstract controller also provided by this package already provide a lot of functionality for typical use cases in web applications. A few examples of those controllers: AbstractController, AbstractCommandController, SimpleFormController.

So basically any direct implementation of the Controller interface just handles HttpServletRequests and should return a ModelAndView, to be further interpreted by the DispatcherServlet. Any additional functionality such as optional validation, form handling, etc should be obtained through extending one of the abstract controller classes mentioned above.

AbstractController
Workflow (and that defined by interface):
1. handleRequest() will be called by the DispatcherServlet
2. Inspection of supported methods (ServletException if request method is not support)
3. If session is required, try to get it (ServletException if not found)
4. Set caching headers if needed according to cacheSeconds propery
5. Call abstract method handleRequestInternal() (optionally synchronizing around the call on the HttpSession), which should be implemented by extending classes to provide actual functionality to return ModelAndView objects.

BaseCommandController
Workflow (and that defined by superclass):
Since this class is an abstract base class for more specific implementation, it does not override the handleRequestInternal() method and also has no actual workflow. Implementing classes like AbstractFormController, AbstractcommandController, SimpleFormController and AbstractWizardFormController provide actual functionality and workflow. More information on workflow performed by superclasses can be found here.

AbstractFormController
Workflow (and that defined by superclass):
1. The controller receives a request for a new form (typically a GET).
2. Call to formBackingObject() which by default, returns an instance of the commandClass that has been configured (see the properties the superclass exposes), but can also be overridden to e.g. retrieve an object from the database (that needs to be modified using the form).
3. Call to initBinder() which allows you to register custom editors for certain fields (often properties of non-primitive or non-String types) of the command class. This will render appropriate Strings for those property values, e.g. locale-specific date strings.
4. Only if bindOnNewForm is set to true, then ServletRequestDataBinder gets applied to populate the new form object with initial request parameters and the onBindOnNewForm(HttpServletRequest, Object, BindException) callback method is called. Note: any defined Validators are not applied at this point, to allow partial binding. However be aware that any Binder customizations applied via initBinder() (such as DataBinder.setRequiredFields(String[]) will still apply. As such, if using bindOnNewForm=true and initBinder() customizations are used to validate fields instead of using Validators, in the case that only some fields will be populated for the new form, there will potentially be some bind errors for missing fields in the errors object. Any view (JSP, etc.) that displays binder errors needs to be intelligent and for this case take into account whether it is displaying the initial form view or subsequent post results, skipping error display for the former.
5. Call to showForm() to return a View that should be rendered (typically the view that renders the form). This method has to be implemented in subclasses.
6. The showForm() implementation will call referenceData(), which you can implement to provide any relevant reference data you might need when editing a form (e.g. a List of Locale objects you're going to let the user select one from).
7. Model gets exposed and view gets rendered, to let the user fill in the form.
8. The controller receives a form submission (typically a POST). To use a different way of detecting a form submission, override the isFormSubmission method.
9. If sessionForm is not set, formBackingObject() is called to retrieve a form object. Otherwise, the controller tries to find the command object which is already bound in the session. If it cannot find the object, it does a call to handleInvalidSubmit which - by default - tries to create a new form object and resubmit the form.
10. The ServletRequestDataBinder gets applied to populate the form object with current request parameters.
11. Call to onBind(HttpServletRequest, Object, Errors) which allows you to do custom processing after binding but before validation (e.g. to manually bind request parameters to bean properties, to be seen by the Validator).
12. If validateOnBinding is set, a registered Validator will be invoked. The Validator will check the form object properties, and register corresponding errors via the given Errors object.
13. Call to onBindAndValidate() which allows you to do custom processing after binding and validation (e.g. to manually bind request parameters, and to validate them outside a Validator).
14. Call processFormSubmission() to process the submission, with or without binding errors. This method has to be implemented in subclasses.
In session form mode, a submission without an existing form object in the session is considered invalid, like in case of a resubmit/reload by the browser. The handleInvalidSubmit method is invoked then, by default trying to resubmit. It can be overridden in subclasses to show corresponding messages or to redirect to a new form, in order to avoid duplicate submissions. The form object in the session can be considered a transaction token in that case.
Note that views should never retrieve form beans from the session but always from the request, as prepared by the form controller. Remember that some view technologies like Velocity cannot even access a HTTP session.
SimpleFormController
Workflow (in addition to the superclass):
1. Call to processFormSubmission which inspects the Errors object to see if any errors have occurred during binding and validation.
2. If errors occured, the controller will return the configured formView, showing the form again (possibly rendering according error messages).
3. If isFormChangeRequest is overridden and returns true for the given request, the controller will return the formView too. In that case, the controller will also suppress validation. Before returning the formView, the controller will invoke onFormChange(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, org.springframework.validation.BindException), giving sub-classes a chance to make modification to the command object. This is intended for requests that change the structure of the form, which should not cause validation and show the form in any case.
4. If no errors occurred, the controller will call onSubmit using all parameters, which in case of the default implementation delegates to onSubmit with just the command object. The default implementation of the latter method will return the configured successView. Consider implementing doSubmitAction(java.lang.Object) doSubmitAction for simply performing a submit action and rendering the success view.
The submit behavior can be customized by overriding one of the onSubmit methods. Submit actions can also perform custom validation if necessary (typically database-driven checks), calling showForm in case of validation errors to show the form view again.