Recipe21.3.Applying Lazy Loading


Recipe 21.3. Applying Lazy Loading

Problem

You want to apply lazy loading techniques to a component of your application.

Solution

Use the Director aspect-oriented design pattern to set up the roles involved in lazy loading as interfaces inside an abstract aspect, as shown in Example 21-6.

Example 21-6. Using the Director aspect-oriented pattern to define the roles that take part in lazy loading
public abstract aspect LazyLoading extends DelegatingProxyPattern {    public interface RealComponent extends Subject    {    }        public interface LazyProxy extends RealComponent    {       public RealComponent getRealComponent( ) throws LazyLoadingException;    }        public abstract LazyProxy initializeComponent(Object configuration); }

The LazyLoading aspect in turn inherits from an implementation of the Proxy pattern, as shown in Recipe 14.6, that focuses on the delegation characteristics of the Proxy pattern, as shown in Example 21-7.

Example 21-7. Specializing the ProxyPattern behavior to focus on delegation
public abstract aspect DelegatingProxyPattern extends ProxyPattern  {    protected boolean reject(       Object caller,       Subject subject,       JoinPoint joinPoint)    {       return false;    }    protected boolean delegate(       Object caller,       Subject subject,       JoinPoint joinPoint)    {       return true;    }    protected Object rejectRequest(       Object caller,       Subject subject,       JoinPoint joinPoint)    {       return null;    } }

Finally, create specialized subaspects of the LazyLoading aspect that will implement the lazy loading behavior for specific components of your target application.

Discussion

Lazy loading involves the loading and instantiation of a class being delayed until the point just before the instance is used. The goal of lazy loading is to dedicate memory resources when necessary by loading and instantiating an object at the point when it is needed.

The LazyLoading aspect in Example 21-6 builds in the DelegatingProxyPattern in Example 21-7 to intercept calls to classes that it is to lazily load on demand. The DelegationProxyPattern in turn specializes the ProxyPattern aspect from Recipe 14.6 to limit the scope to a delegation form of proxy.

The RealComponent interface declared in the LazyLoading aspect is applied by specialized subaspects to any classes within the target application to be lazily loaded. You need a proxy object to store the information by which the real class can be instantiated when needed and this role is provided by the LazyProxy interface.

The LazyProxy interface offers enough functionality to work with the real components without having to load them. The LazyProxy defines a single method which is called to load the real component when needed.

Finally, the LazyLoading abstract aspect defines the abstract initializeComponent(Object) method which is implemented by subaspects to instantiate lazy proxies in place of the real components.

Example 21-8 shows how the abstract LazyLoading aspect can be applied to an example application.

Example 21-8. Applying the LazyLoading abstract aspect to an application's classes
package com.oreilly.aspectjcookbook.feature_management; import org.aspectj.lang.JoinPoint; import com.oreilly.aspectjcookbook.lazyloading.LazyLoading;        import com.oreilly.aspectjcookbook.lazyloading.LazyLoadingException; import com.oreilly.aspectjcookbook.features.Feature; public aspect LazyFeatureLoading extends LazyLoading {    declare parents : Feature implements RealComponent;        declare parents : LazyProxy implements Feature;    public LazyProxy initializeComponent(Object object)    {       LazyProxy proxy =          new LazyFeatureProxy((String) object);       return proxy;    }        protected pointcut requestTriggered( ) :        call(* com.oreilly.aspectjcookbook.features.Feature.* (..)) &&       !within(com.oreilly.aspectjcookbook.oopatterns.ProxyPattern+);        protected Object delegateRequest(       Object caller,       Subject subject,       JoinPoint joinPoint)    {       if (subject instanceof LazyFeatureProxy)       {          LazyFeatureProxy feature =             (LazyFeatureProxy) subject;                    try          {             Feature implementedFeature =                (Feature) feature.getRealComponent( );                          implementedFeature.doSomething(                   (String) joinPoint.getArgs( )[0]);                       }          catch (LazyLoadingException lle)          {             lle.printStackTrace( );             lle.getOriginalException( ).printStackTrace( );             System.out.println(                   "Exception when attempting to "                   + "lazy load"                   + " a particular class,"                   + " aborting the call");          }       }       else       {                   ((Feature) subject).doSomething(                (String) joinPoint.getArgs( )[0]);       }       return null;    }        private class LazyFeatureProxy implements Feature, LazyProxy    {       private Object configuration;       private Feature delegate;       public LazyFeatureProxy(Object configuration)       {          this.configuration = configuration;       }              public synchronized RealComponent getRealComponent( )          throws LazyLoadingException       {          if (this.configuration instanceof String)          {             try             {                if (this.delegate == null)                {                   return this.delegate =                      (Feature) Class                      .forName((String) this.configuration)                      .newInstance( );                }                else                {                   return this.delegate;                }             }             catch (Exception e)             {                throw new LazyLoadingException(                   "Exception raised when loading real component", e);             }          }          else          {             throw new LazyLoadingException("Error in configuration");          }       }              public void doSomething(String message)       {       }    } }

The LazyFeatureLoading aspect encapsulates how to lazily load the category of classes that implement the Feature interface. The two declare parent statements specify that any class implementing the Feature interface meets the RealComponent role and that the LazyProxy can replace a Feature to fulfill its role of providing a proxy for any Feature objects.

The initializeComponent(Object) method returns a LazyProxy instance set up with the necessary configuration to load the real component. The initializeComponent(Object) method is called whenever the target application decides that a particular instance is to be lazily loaded.

The requestTriggered(..) pointcut and the delegateRequest(..) method are required by the abstract DelegatingProxyPattern. The requestTriggered(..) pointcut is used to capture all calls to methods on classes that implement the Feature interface. Additional protection is provided to stop the LazyFeatureLoading aspect advising itself when the method being called on a LazyProxy is called by the aspect.

The delegateRequest(..) method examines the subject being called to see if it is an instance of the LazyfeatureProxy class. If the subject is an instance of LazyFeatureProxy, the getrealComponent( ) method is called to load the real component. The method call is then forwarded to the real component.

Finally, the LazyFeatureLoading aspect defines the LazyFeatureProxy class. This class contains all of the information necessary to load the corresponding real Feature implementation should a method be called. The loading of the real Feature implementation is performed by the getrealComponent() method required by the LazyProxy interface.

Example 21-9 shows how the LazyFeatureLoading aspect is used by an example application to support the lazy loading of the FeatureA and FeatureB classes. In this example, both of these classes implement the Feature interface.

Example 21-9. Using the LazyFeatureLoading aspect in an example application
public class MainApplication {    private Feature[] features;    public MainApplication( )    {       features = new Feature[2];              features[0] =          LazyFeatureLoading             .aspectOf( )             .initializeComponent(             "com.oreilly.aspectjcookbook.features.FeatureA");       features[1] =          LazyFeatureLoading             .aspectOf( )             .initializeComponent(             "com.oreilly.aspectjcookbook.features.FeatureB");              features[0].doSomething("Hello there");       features[0].doSomething("Hello again");       features[1].doSomething("Hi to you too");       features[1].doSomething("Hi again");    }    public static void main(String[] args)    {       MainApplication mainApplication =          new MainApplication( );    } }

See Also

The call(Signature) pointcut is described in Recipe 4.1; the within(TypePattern) pointcut is described in Recipe 9.1; the AND (&&) operator and the OR (||) operator are described in Recipes 12.2 and 12.3 respectively; using inheritance to implement abstract aspects is explained in Recipe 15.2; creating a delegating proxy pattern using aspects is shown in Recipe 18.6; the Director aspect-oriented design pattern is explained in Recipe 23.2.



AspectJ Cookbook
Aspectj Cookbook
ISBN: 0596006543
EAN: 2147483647
Year: 2006
Pages: 203
Authors: Russ Miles

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net