|
YOUR FEEDBACK
Did you read today's front page stories & breaking news?
SYS-CON.TV |
TOP THREE LINKS YOU MUST CLICK ON Caching Proxy Cache
A practical implementation
By: Justin Knowlden
Feb. 8, 2006 09:00 AM
A proxy cache is a behavioral technique that provides the ability to cache a result-set (output) from a service call via a proxy using the argument-set (input) as the cache key. Through this proxy, all calls to any concrete instances of a defined type, service, are made. In this proxy, input is used as the key to obtain from or provide to a cache the output from a called service. If output has already been cached for a given input, the proxy returns the cached output without forwarding the call to the actual service.
Although this article does refer to caching, it's not about caching. Instead, this article attempts to provide a description of how to incorporate a feature, such as caching, modularly and without major impact to existing code. Provided first is a description of how my colleagues and I ended up at a proxy cache and is followed by a generic summary of how to design and implement a proxy cache solution.
Background The service layer was fairly simple in that most of the services were read-only with some basic business logic applied behind the scenes. We were not using any object/relational (O/R) mapping tools, just basic Data Access Objects (DAOs) and, therefore, several ideas were tossed around. One idea was to simply use an O/R tool. Any good O/R tool would include a caching mechanism to avoid hitting the database unnecessarily. However, we decided against this for a couple of reasons:
Another viable option for us was to introduce caching code into each service, but this was not suitable either as it violated some of our principles. The SRP was violated when the service would have been responsible for its normal, expected behavior and also caching. OAOO was violated when we would have had to introduce the same code into each service. We could have abstracted the behavior into a base class or supporting utility class, but SRP would still have been violated, so why bother.
Proxy Cache Java does not have extensive built-in support for Aspect-Oriented Programming, and we did not want to introduce an AOP extension such as AspectJ. However, Java does provide built-in support for proxies via the dynamic proxy class (proxy class), provided by the standard Java platform since JDK1.3. A proxy class could be used to encapsulate our needed behavior without violating our core principles and making us feel all "dirty." From this idea was born our concept of a proxy cache. Note: The choice to not use an O/R mapping tool does not negate using one in the future. You could potentially use a proxy cache and an O/R mapping tool concurrently.
Dynamic Proxy In Java, there are obviously many ways that a proxy can be implemented, but this article will utilize the well-established proxy class, java.lang.reflect.Proxy. Using a proxy class will allow the proxy cache to disguise itself as the service without implementing any user-defined interfaces. The basic protocol for using the proxy class is as follows:
InvocationHandler handler = In your invocation handler you are required to implement an invoke() method that must accept the proxy instance, a reference to the method that is being called on that instance, and any arguments that are being passed to that instance. In this invoke() method you can provide an epilogue and/or prologue to the actual method call; i.e., you can "wrap" the intended method call with your own custom behavior. The invocation handler must also have access to a concrete instance of the desired object. This is perhaps the trickiest aspect of the proxy class framework as it requires a priori knowledge of the caller's intentions or a very specific implementation of an invocation handler. In the case of the proxy cache, the most useful implementation is to pass the concrete object as an argument to the constructor of the invocation handler. This, however, implies a bijectional relationship between the proxy and the proxied object, which may only be bad if there is an explosion of objects needing a proxy.
Implementing a Proxy Cache Shown in Figure 1 is a simple entity relationship diagram of the framework that will be implemented. Generally, you will already have everything shown in the diagram well established in your system except for CacheProxy. Why? Because you're not going to introduce a proxy cache until you actually need it. Introduce caching only when you know there is a problem. In Figure 1, all interfaces are illustrated as a rounded-rectangle. As is shown, the Service interface knows only about itself:
package service; The CacheProxy class knows about the service and is an implementation of the InvocationHandler interface. Finally, the ServiceFactory knows about everything service related (including the Concrete Service, albeit implicitly). Where does the caching behavior go? The responsibility of caching firmly belongs to CacheProxy. But, how is the CacheProxy created so that it may enable caching? Normally, the ServiceFactory would create a Concrete Service and basically return it. When utilizing proxy cache, ServiceFactory will still create the Concrete Service instance, but will pass that instance to a new instance CacheProxy and return the CacheProxy instance instead. Therefore, whenever a method is called on the service (even those not defined in the service interface), the call will be trapped by the CacheProxy, wherein a cache can be investigated prior to passing the call on to the Concrete Service. LATEST JAVA STORIES & POSTS
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
|
SYS-CON FEATURED WHITEPAPERS MOST READ THIS WEEK SPONSORED BY INFRAGISTICS
BREAKING JAVA NEWS
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||