Friday, September 18, 2015

Spring Scopes – Decoupling code

Spring Scopes – Decoupling code


The Scenario

I have an application that has a lot of classes – more than 10. To simplify the issue, let’s say that I have a system that represents a school. So I will have a school class, a room class, teacher and all the rest, for example:
class School(){
  val classes : List[Class]
  def gotMoney(total: int)
}
class Class(){
  val teachers: List[Teacher]
  def updateTeacher(raise: int)
}
class Teacher(){
  def updateTeacherSalary(raise: int)
}

So we have in place - a school that has a list of classes that each has a list of teachers. The normal flow is that the school gets money and wants to give it to each teacher. So we have a method to pass the information from the School to the Class and then to each teacher.
Let’s say that I have a web application that calls the system, and we want to add a profile parameter that is sent during run time so that we can filter which teacher’s get a raise and which don’t.
How do we pass this new parameter from the Web API to the teacher class?

The Solution


Strait forward

A classic scenario is to add a new parameter “profile” to all the methods that need the profile. The limitation of this way is that we might want to add more than one parameter. In addition this is a legacy application that has a lot of spaghetti, so this would mean adding the parameter to a lot of methods that don’t really need to know about this.
What we really need is a way for a bunch of parameters to be entered in the Web API level and then be available to other places of code.

Scope Solution

Assumptions

The current assumption is that we have spring in place and that most of the service classes are spring beans.
So the actual solution is to create a session bean with scope prototype so that   we have a new bean each time that we need it. The bean is created on the Web API level and populated with the values, then in the lower level API the services that needs the new parameters will request the same prototype bean and get the values.
By using the prototype bean we also insure that are application can support multithreading and keep multiple instances of each session.

Standard web solution

If each bean will inject a standard prototype bean then each inject will get a new bean and the values will not persist. What we want is create only one bean per http request. For this spring invented a bean with scope of HttpRequest (http://www.tutorialspoint.com/spring/spring_bean_scopes.html). So what happens is that each time you request this bean spring will check if for this specific http request a bean has already been created. If yes you get the reference and if no you will get a new one.
For this to work your application must be a web-aware Spring Application Context. This is so that spring will hook into the http requests and know when to create a new instance.
But what if you want to use this same mechanism but you don’t have a web-aware context? If you did not have spring, the obvious solution would be to store the data you need on the local thread and then you can have access to it from any other class.
So spring actually supports another type of scope that is not in the standard documentation – thread.

Thread Scope

To definite your bean, you will use the standard definition of:
<bean id="sessionData" class="com.company.SessionData" scope="thread"/>

Spring has a class that implements the thread scope which is: SimpleThreadScope. It is a simple implementation with the limitation that it does not support a callback for the destruction of the bean, since it does not know when the thread is finished.
Since this is an unreleased class it is not supported by default and to use it you must register it with spring like any other custom spring bean:

<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>

.

Summary


When you need to change a lot of code due to API changes, you need to think out of the box and find a solution to magically pass the parameters from one section of the code to another. The solution to this is to isolate the parameters in a spring bean using the proper scope of the bean. You need to read up on spring scopes to find the specific scope that you need. Of course you always have the option to implement your own scope