Proxy pattern applied to enable caching - a very simple Web Application
Recently I switched to work for another customer (Bank\Trading) and one of the first activities, in order to offer a more structured and well-designed product to users, was to reduce the overhead and the Database accesses. Considering that I am working on a web portal with 2 millions of contacts per month and hundreds of user accounts, designed and developed more than 10 years ago, it is very difficult to adopt any Java Framework and, in general, to implement whatever big modification. I studied several solutions to optimize the system’s performances. One of the pattern that comes to help in my work is the Proxy Pattern. I’m going to show you some aspects of this pattern, related to caching objects and data. This article is divided into two parts, one for each solution that I found to this issue. We’ll go into a very simple web application: NO dependency injection this time, NO Spring, NO Frameworks, only very simple code. We’ll create a simple web app that on home page will print the timestamp of last created instance of cached object. Consider that this object may be a complex data structure from a database, or a big image or something very painful for server. For our purpose, things are simplified. Well, we can summarize: 1. user requires an object 2. system check: an instance of this object already is created? 3. If no, it create a new instance, otherwise it give back the already made instance. 4. The user, transparently, receives the object. Let’s go! Configure Eclipse. Just create a New Dynamic Web Project, I called proxycacheapp. I used this project for both solutions that I’m going to implement. UML Class Diagram of a classical Proxy pattern from original GoF book, is:
And, briefly:
the JSP contains the code for execute the request,
that is wrapped by Servlet Filter (declared in web.xml as I hope you already know),
Servlet Filter calls our ProxyService to achieve what user wants.
ProxyService is only a surrogate, if the object required is ready and already created, it give back to user the cached instance, otherwise Proxy calls concrete RealService and require to create a new one.
Object (either brand new or cached) is sent to output of ServletFilter, that incapsulate it into HttpRequest and, later Jsp prints it on Web page.
Simple.
This is a general scenario, but pragmatic implementation, can be made using two different solutions.
Solution 1
Plain, classical, proxy pattern applied.
This solution uses only diagrams and the previous explanation, no more complication.
Domain Object
It is very useless here, but I want to show you that it is possible to use any custom Object in this approach.
Let’s create a new object, a POJO, with an ID and a timestamp..later we’ll print timestamp on JSP.
Create new Java Class on Eclipse and write th wolling code (I use it.nickg.utils package):
package it.nickg.utils; public class Timestamp { private long id; private String timestamp; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getTimestamp() { return timestamp; } public void setTimestamp(String timestamp) { this.timestamp = timestamp; } }
This is our Domain object. Now let’s implement the Proxy Pattern, first create a new interface (package is it.nickg.services):
package it.nickg.services; import it.nickg.utils.Timestamp; public interface TimestampService { /** * retrieve an istance of Timestamp object * * @return Timestamp object */ public Timestamp getTimestamp(); }
Then let’s write the Real implementation
of Service, that creates instance of our Domain Object, it implements our previously
created interface:
package it.nickg.services; import it.nickg.utils.Timestamp; import java.util.Date; public class TimestampServiceReal implements TimestampService { @Override public Timestamp getTimestamp() { Date time = new Date(); Timestamp timestamp = new Timestamp(); timestamp.setId(time.getTime()); timestamp.setTimestamp(time.toString()); return timestamp; } }
Not best solution for getting a timestamp,
I know, but it is only for a learning purpose. Look at the concept.
package it.nickg.services; import it.nickg.utils.Timestamp; public class TimestampServiceProxy implements TimestampService { private TimestampServiceReal timestampServiceReal; public Timestamp timestamp; @Override public Timestamp getTimestamp() { // Proxy checks if a real instance of service (and of timestamp object) // already is created if (timestampServiceReal == null) { timestampServiceReal = new TimestampServiceReal(); timestamp = timestampServiceReal.getTimestamp(); } // return required object return timestamp; } }
Now, It’s time to code our front-end!
Most of the work is done through a Servlet
Filter that wraps request, calls our services and sets a parameter in
HttpResponse, with results.
Servlet Filter must be declared in
web.xml:
(complete web.xml code)
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <filter> <filter-name>TimestampFilter</filter-name> <filter-class>it.nickg.servlets.TimestampFilter</filter-class> </filter> <filter-mapping> <filter-name>TimestampFilter</filter-name> <url-pattern>/index.jsp</url-pattern> </filter-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
Here Servlet Filter code:
package it.nickg.servlets; import it.nickg.services.TimestampService; import it.nickg.services.TimestampServiceProxy; import it.nickg.utils.Timestamp; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class TimestampFilter implements Filter { TimestampService tsService = new TimestampServiceProxy(); public TimestampFilter() { // TODO Auto-generated constructor stub } @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { Timestamp timestamp = null; // retrieve a timestamp from service timestamp = tsService.getTimestamp(); request.setAttribute("timestamp", timestamp); // forward output chain.doFilter(request, response); } @Override public void init(FilterConfig filterConfig) throws ServletException { // TODO Auto-generated method stub } }
Last step is about editing index.jsp, and
let display the creation’s timestamp of Domain Object:
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%> <%@page import="it.nickg.utils.Timestamp"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>Proxy Pattern Example</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <h3>Domain object is created:</h3><br> <% Timestamp timestamp = (Timestamp)request.getAttribute("timestamp"); out.print(timestamp.getTimestamp()); %> </body> </html>
I HATE to use scriplet and Java code in
JSPs, use jstl, struts taglib, any other technology. Especially in production
code.
That’s all, now run our server inside
Eclipse (I use tomcat)
Right click on project -> Run as -> Server Application.
Now on welcome page, it displays first
creation timestamp of the object and if you refresh the page, the timestamp
doesn’t change:
It is cached!!
Simple, isn’t?
Well, It’s time for more complicated
issues.
Solution 2
A more experienced reader can found my
previous solution a bit like “reinventing the wheel” and it’s in part true,
because java offers a Proxy class:
java.lang.reflect.Proxy
Using Java reflection it is possible to
implement a more elegant representation of Proxy Pattern.
package it.nickg.services; import java.lang.reflect.Proxy; public class TimestampServiceFactory { public TimestampService createService() { return (TimestampService) Proxy.newProxyInstance( TimestampService.class.getClassLoader(), new Class[] { TimestampService.class }, new TimestampReflectProxy(new TimestampServiceReal())); } }
Here we use Proxy.newProxyInstance() to
call a proxy. It returns an instance of a proxy class for the specified
interfaces that dispatches method invocations to the specified invocation
handler(TimestampReflectProxy).
package it.nickg.services; public interface CacheIFace { /** * Retrieve object from cache * * @param key * @return cached object */ public Object getCache(Object key); /** * Put a new object in cache * * @param key * @param value */ public void putCache(Object key, Object value); }
and an implementation class Cache:
package it.nickg.services; import java.util.HashMap; import java.util.Map; public class Cache implements CacheIFace { private Map<Object, Object> values; public Cache() { this.values = new HashMap<Object, Object>(8); } public Object getCache(Object key) { return values.get(key); } public void putCache(Object key, Object value) { values.put(key, value); } }
These comes to let us perform caching
feature through an HashMap:
HashMap IS the cache.
package it.nickg.services; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.Arrays; public class TimestampReflectProxy implements InvocationHandler { private final Object obj; private CacheIFace caches; private static final Object NullKey = new Object(); public TimestampReflectProxy(Object toProxy) { this.obj = toProxy; this.caches = new Cache(); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { CacheIFace cache = (CacheIFace) caches.getCache(method); if (cache == null) { caches.putCache(method, cache = new Cache()); } Object argsList = args != null ? Arrays.asList(args) : NullKey; Object cacheValue = cache.getCache(argsList); if (cacheValue == null) { cache.putCache(argsList, cacheValue = method.invoke(obj, args)); } return cacheValue; } }
And, finally, here is the ServletFilter
modified:
package it.nickg.servlets; import it.nickg.services.TimestampService; import it.nickg.services.TimestampServiceFactory; import it.nickg.utils.Timestamp; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class TimestampFilter implements Filter { // TimestampService tsService = new TimestampServiceProxy(); TimestampServiceFactory tsFactory = new TimestampServiceFactory(); TimestampService tsService = tsFactory.createService(); public TimestampFilter() { // TODO Auto-generated constructor stub } @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { Timestamp timestamp = null; // retrieve a timestamp from service timestamp = tsService.getTimestamp(); request.setAttribute("timestamp", timestamp); // forward output chain.doFilter(request, response); } @Override public void init(FilterConfig filterConfig) throws ServletException { // TODO Auto-generated method stub } }
I try to explain this magic trick.
Our TimestampReflectProxy class has two
private attributes, obj and caches.
When user requires the page, the
TimestampFilter acts as wrapper, it catches the request and calls
TimestampServiceFactory and TimestampService that requires to create the
service.
First time, it passes TimestampServiceReal
as Object to TimestampReflectProxy ‘s
constructor, so:
- obj is an instance of
TimestampServiceReal;
- a new instance of Cache is created;
Then the filter calls getTimestamp()
method and this call is caught with reflection:
- it enters in invoke() method,
- it checks if an occurrence of method is
already present in caches,
- there isn’t the required occurrence and
so cache is null,
- it puts a new entry in cache;
- then retrieve the args list and checks
if there is an entry in cache with given key;
- if not, it create a new one invoking
method;
From this time, every time the user
refreshs the web page, the application using reflection, finds existing entries
in cache, skips checks, and gives back to him.
While this second solution seems very
interesting, advanced, elegant and cool..there are several drawbacks:
(cut and paste from Sun)
Performance Overhead
Because reflection involves types that are dynamically resolved, certain
Java virtual machine optimizations can not be performed. Consequently,
reflective operations have slower performance than their non-reflective
counterparts, and should be avoided in sections of code which are called
frequently in performance-sensitive applications.
Security Restrictions
Reflection requires a runtime permission which may not be present when
running under a security manager. This is in an important consideration for
code which has to run in a restricted security context, such as in an Applet.
Exposure of Internals
Since reflection allows code to perform operations that would be illegal
in non-reflective code, such as accessing private fields and methods, the use
of reflection can result in unexpected side-effects, which may render code
dysfunctional and may destroy portability. Reflective code breaks abstractions
and therefore may change behavior with upgrades of the platform.
Some interesting discussions are linked
above between references.
Enough to avoid it in my particular use
case.
Last thing I want to show.
Perhaps more careful of you have observed
that when an instance of an object is created, it can live forever!
(Well, I know, it’s impossible, but “undefined”
and “forever” are both unacceptable in my opinion).
Best way to give the capability of
periodical refresh of object, is implementing a TimeToLive Strategy. (Other
possible solutions are LRU and LFU).
I’ll not describe here now, but give you
some input:
Into our Cache class, it is necessary to
code a thread that periodically cleans the cache and you can use whatever
policy you want.
That’s all folks!
Please, feel free to add comment and
critics to my article, they are very useful.
References:
About Reflection:
About reflection performances: