.jpg?alt=media&token=7f5e6011-729e-4df8-bbe4-e97d3ab885a8)
Pointcuts Explained: Spring AOP vs. AspectJ in Handling Cross-Cutting Concerns - Part 1
Written by Danubius IT Solutions
Part 1 – Theoretical Insights
As software systems grow in complexity, efficiently managing cross-cutting concerns becomes increasingly challenging. Pointcuts, a central feature in Aspect-Oriented Programming, are essential for defining where exactly these concerns should take effect in the application flow. AOP frameworks, however, may vary significantly as far as their approach, implementation and flexibility are concerned. In this two-part series, we will explore the key differences between Spring AOP and AspectJ with pointcuts in focus, giving you a clear understanding of how to harness the power of AOP in your Java Spring projects.
Key Concepts
Before we could dive deep into the exploration of pointcuts in practice, it is important to gain insight into the key concepts of Aspect-Oriented Programming as well as some crucial differences between Spring AOP and AspectJ. This article – the first part of the series – concentrates on theory, comparing and contrasting the two AOP frameworks at a conceptual level.
Aspect-Oriented Programming is a programming paradigm that allows the separation of cross-cutting concerns (like logging, security and transaction management) from the main business logic of an application. The modularization of behaviours that affect multiple classes is achieved via aspects, which define where and how additional functionality should be applied across the application. The action taken by the aspect is called advice. Different types of advice include "around", "before", and "after". Advice is always associated with a pointcut expression and it runs at any join point – specific points during the execution flow of the program, such as method calls, object instantiations, field access or exception handling – matched by the pointcut. Last but not least, weaving means the linking of aspects with other application types or objects to create an advised object. This can happen at compile time, load time or at runtime.
Spring AOP and AspectJ, two separate implementations of AOP, are both built up alongside the above core principles. AOP-related resources on the Internet do not always specify which one they are talking about, as if they were interchangeable. However, the two frameworks differ in numerous ways and are also designed to be used in distinct scenarios. The following comparison highlights their major differences.
Spring AOP vs. AspectJ
1. Scope
Spring AOP is a simple AOP implementation across Spring IoC. Since it works at the Spring container level, its aspects only affect Spring-managed beans. AspectJ, on the other hand, is framework-independent. AspectJ aspects can be applied to any Java class. This offers greater flexibility and availability both within and outside of Spring applications.
2. Weaving
While Spring AOP offers only runtime weaving, AspectJ allows compile-time, post-compile and load-time weaving. The two frameworks work with different underlying implementations.
Spring AOP is proxy-based: aspects are woven during execution via proxies of the advised objects. A proxy can be thought of as a wrapper that passes method invocations through its handlers, adding the functionality of the advice. A JDK dynamic proxy is used when the target object implements at least one interface: the proxy class will implement it, too. Thus it is actually the interface that is being proxied and its methods advised. If, however, the target object does not implement any interfaces, a CGLIB proxy will be used: in this case, the proxy will extend the class. The fact that CGLIB proxies utilize subclassing implies that they do not work on final classes; also, final or static methods cannot be advised (as they are not overridable).
When working with Spring AOP it is important to understand that method calls on the object reference of the advised class are in fact calls on the proxy, the "wrapper". The call is delegated to the interceptors (i.e., the advice), and the targeted method itself gets invoked. As a result, calls within the target object are not intercepted. Obviously, JDK dynamic proxies only intercept public interface method calls. While technically CGLIB proxies allow public, protected and package-private method call interception, it is strongly recommended to advise methods with public signatures only.
AspectJ, on the contrary, does not use proxying, hence runtime weaving is not available in it, either. It introduces its own compiler (ajc) and some small runtime dependencies (aspectjrt, aspectjweaver). Compile-time weaving is the most common approach. Whenever the source codes of both the aspects and that of the advised objects are accessible, the AspectJ compiler will compile from source, and produce the woven classes. The bytecode is modified to incorporate the additional behaviour. Upon execution, the output class of the weaving process is loaded into the JVM as a normal Java class. Post-compile weaving (also called binary weaving) is used to weave existing class files and JAR files. The aspects may either be in source or binary form, and may themselves be woven by other aspects. At last, load-time weaving is also binary weaving, deferred until the class loader loads the given class file. To integrate AspectJ into the Maven build process, Mojo’s AspectJ Maven Plugin is the most convenient and widely used tool.
3. Join points
In Spring AOP, only method execution join points are supported. The reason for this limitation lies in the proxy-based nature of the framework, proxies intercepting method calls and adding the behaviour of the advice before, after or around the method invocation. AspectJ is considerably more flexible in this sense as well, and provides more fine-grained control: method calls and executions, constructor calls and executions, static initializer executions, object instantiations, field references, exception handler executions etc. may all serve as potential join points. Call and execution are two different points during the program flow – we will come back to this in the second part of the series in more detail.
4. Pointcut expressions
Spring AOP uses a limited subset of AspectJ’s pointcut expression language. It can define pointcuts at the method level but lacks the complexity and variety of expressions that AspectJ offers. Spring AOP pointcut designators are: execution, within, this, target, args, @target, @args, @within, and @annotation. An additional pointcut designator called bean is Spring-specific, it is not present in native AspectJ weaving. The full AspectJ pointcut language, in turn, supports further pointcut designators, which are not available in Spring AOP: call, get, set, preinitialization, staticinitialization, initialization, handler, adviceexecution, withincode, cflow, cflowbelow, if, @this and @withincode. In both frameworks, pointcut expressions may contain wildcards and can be combined by using the &&, || and ! logical operators.
5. Performance
In Spring AOP, the creation of proxy classes and through them a couple of more method invocations to intercept the advised target methods affect the performance negatively. In AspectJ, however, since aspects are woven directly into the bytecode, there is no need for proxies at runtime, which reduces overhead. In general, we can state that AspectJ performs better due to its compile-time or load-time weaving, which is considerably faster than runtime weaving.
6. Complexity and ease of use
Last but not least, it should be pointed out that Spring AOP is easier and more convenient to use for basic AOP needs. It is designed to be lightweight, and does not have a steep learning curve. Spring AOP is best suited for simple, enterprise-level concerns like transaction management, logging and security, where method-level interception is sufficient. It fits well into typical Spring-based applications. AspectJ is definitely more complex due to its powerful and rich feature set, and calls for deeper knowledge of AOP concepts and the AspectJ syntax. As it also comes with its own compiler, it requires some extra configuration, and might be difficult to combine with other libraries that modify or generate code in the compilation phase (like Lombok, for example). AspectJ is ideal for advanced use cases where fine-grained control over aspects and performance optimizations are needed.
Summary
The key differences that we have reviewed are summarized in the table below:
Spring AOP | AspectJ | |
Scope | Spring-managed beans | any Java class |
Weaving | runtime weaving, proxies | compile-time, post-compile and load-time weaving |
Join points | only method execution | method calls, executions, initializations, field reference etc. |
Pointcut expressions | limited subset of AspectJ’s pointcut expression language | a wide variety of expressions |
Performance | higher runtime overhead | better performance |
Complexity | basic AOP needs in Spring apps | complex, for advanced use cases |
Now that we have a clear picture of the two AOP frameworks’ main characteristics as well as their underlying implementations, it is time to get practical. The second part of this blog series focuses on pointcuts in both Spring AOP and AspectJ, exploring their working mechanisms with the help of code examples.
Resources
https://docs.spring.io/spring-framework/docs/4.3.15.RELEASE/spring-framework-reference/html/aop.html
https://docs.spring.io/spring-framework/reference/core/aop.html
https://www.baeldung.com/aspectj
https://www.baeldung.com/spring-aop
https://www.baeldung.com/spring-aop-vs-aspectj
The article was written by Zsuzsanna Benkő, software developer at Danubius IT Solutions.
Interested in IT solutions tailored to your business? Contact us for a free consultation, where we'll collaboratively explore your needs and our methodologies.