Introducing the Aspects

Finally, four aspects are declared to encapsulate lazy loading in the example application. The ProxyPattern, DelegatingProxyPattern, LazyLoading, and TraceLazyInitialization aspects.

The ProxyPattern aspect and its derived DelegatingProxyPattern aspect are not shown here, but can be found in the full source for this example. Both of these aspects provide a hierarchy that supports a generic reusable abstract foundation that encapsulates the GoF Proxy Design Pattern, in particular the delegation characteristics of the pattern.

The Proxy Pattern, particularly in its delegation mode as the DelegatingProxyPattern that specializes the pattern to, is an ideal base for a lazy-loading system, as it provides a means by which control can be gained to any and all calls to an object. The original Proxy Pattern AspectJ implementation adapted for this example came from the research completed by Gregor Kiczales and Jan Hannemann.

The LazyLoading aspect as shown in the following code snippet encapsulates the specific application of the proxy pattern to the lazy-loading policies. It defines the logic to capture messages for the concrete target objects so that they can be initialized if necessary and then the message passed on. If the object already exists then the message is simply passed on without any additional instantiation.

Finally, the TraceLazyInitialization aspect, as shown in the final code snippet below, merely provides a testing capability for the application to produce the output analyzed for the Summary and Conclusion to this article. This aspect merely examines each of the applications join points to provide an effective trace of when and where particular loading and initializations occurred to provide proof that lazy loading is indeed happening.

Summary and Conclusion

The example has shown that although the AspectJ version is certainly more complicated, it does have some significant advantages over the more traditional OO implementation of lazy loading. The most powerful advantage is that the lazy-loading logic is modularized and encapsulated within the LazyLoading aspect, rather than spread throughout the business logic classes. Therefore it can be amended and managed in a central location rather than the maintenance nightmare that could occur if changes had to be made to the mechanism in more traditional implementations.

An additional benefit is that to remove lazy loading would simply involve changing the initialization calls in the main method to initialize the concrete class instances directly. This would effectively remove the lazy-loading behavior should it not be needed with only a very simple change, rather than the fundamental architecture change that would be necessary in an OO-only system.

It is worth pointing out that there are several interesting features of AspectJ that have been included in this example that may confuse the beginner. AspectJ allows you to define default behavior on interfaces and this has been done in this case as part of the LazyLoading aspect affecting the Feature interface.

The default behavior leaves the interface as still being an interface, but also provides default behavior for specific areas of the interface to give the implementing classes the option of implementing that behavior or not.

In this example the LazyFeature did not need to implement the behavior for the doSomething(String) method since the message was only being used for interception by the lazy-loading aspect and so a default empty implementation was provided. However, the external feature developers would still be forced to implement the method since they would not be applying the LazyLoading aspect as part of their development, and therefore would only see the interface definition.

The apparent disparity between the default implementation of the doSomething(String) method being declared in the LazyLoading aspect could have been alleviated to some degree by declaring a static inner aspect in the Feature interface. However, this would have forced the implementers of the concrete features using the source code for the interface to use AspectJ to compile against the Feature interface. This constraint was avoided by placing the lazy-loading aspect specific extensions to the Feature interface in the aspect only.

In conclusion, although lazy loading can certainly be implemented effectively using traditional Object-Oriented methods only, the crosscutting nature of lazy loading is an ideal candidate for using an Aspect-Oriented approach, improving modularization in various fundamental ways.

Russell Miles
is a senior consultant for SpringSource in the UK and contributes to various open source projects while working on books for O'Reilly.