Spring Framework is developed on two core concepts – Dependency Injection and Aspect-Oriented Programming (AOP). Today we will look into the core concepts of Aspect-Oriented Programming and how we can implement it using Spring Framework.
Aspect-Oriented Programming Overview
Most of the enterprise applications have some common crosscutting concerns that is applicable for different types of Objects and modules. Some of the common crosscutting concerns are logging, transaction management, data validation, etc. In Object-Oriented Programming, modularity of application is achieved by Classes whereas in Aspect-Oriented Programming application modularity is achieved by Aspects and they are configured to cut across different classes.
AOP takes out the direct dependency of crosscutting tasks from classes that we can’t achieve through a normal object-oriented programming model. For example, we can have a separate class for logging but again the functional classes will have to call these methods to achieve logging across the application.
Aspect-Oriented Programming Core Concepts
Before we dive into the implementation of AOP in Spring Framework, we should understand the core concepts of AOP.
- Aspect: An aspect is a class that implements enterprise application concerns that cut across multiple classes, such as transaction management. Aspects can be a normal class configured through Spring XML configuration or we can use Spring AspectJ integration to define a class as Aspect using
@Aspect
annotation. - Join Point: A join point is a specific point in the application such as method execution, exception handling, changing object variable values, etc. In Spring AOP a join point is always the execution of a method.
- Advice: Advices are actions taken for a particular join point. In terms of programming, they are methods that get executed when a certain join point with a matching pointcut is reached in the application. You can think of Advice as Struts2 interceptors or Servlet Filters.
- Pointcut: Pointcut is an expression that matchs with join points to determine whether advice needs to be executed or not. Pointcut uses different kinds of expressions that are matched with the join points and Spring framework uses the AspectJ pointcut expression language.
- Target Object: They are the object on which advices are applied. Spring AOP is implemented using runtime proxies so this object is always a proxied object. What it means is that a subclass is created at runtime where the target method is overridden and advice are included based on their configuration.
- AOP proxy: Spring AOP implementation uses JDK dynamic proxy to create the Proxy classes with target classes and advice invocations, these are called AOP proxy classes. We can also use CGLIB proxy by adding it as the dependency in the Spring AOP project.
- Weaving: It is the process of linking aspects with other objects to create the advised proxy objects. This can be done at compile-time, load time, or at runtime. Spring AOP performs weaving at the runtime.
AOP Advice Types
Based on the execution strategy of advice, they are of the following types.
- Before Advice: These advice runs before the execution of join point methods. We can use @Before annotation to mark an advice type as Before advice.
- After (finally) Advice: An advice that gets executed after the join point method finishes executing, whether normally or by throwing an exception. We can create after advice using @After annotation.
- After Returning Advice: Sometimes we want advice methods to execute only if the join point method executes normally. We can use @AfterReturning annotation to mark a method as after returning advice.
- After Throwing Advice: This advice gets executed only when the joint point method throws an exception, we can use it to roll back the transaction declaratively. We use
@AfterThrowing
annotation for this type of advice. - Around Advice: This is the most important and powerful advice. This advice surrounds the join point method and we can also choose whether to execute the join point method or not. We can write advice code that gets executed before and after the execution of the join point method. It is the responsibility of around advice to invoke the join point method and return values if the method is returning something. We use
@Around
annotation to create around advice methods.
The points mentioned above may sound confusing but when we will look at the implementation of Spring AOP, things will be more clear. Let’s start creating a simple Spring project with AOP implementations. Spring provides support for using AspectJ annotations to create aspects and we will be using that for simplicity. All the above AOP annotations are defined in org.aspectj.lang.annotation
package.
Spring AOP AspectJ Dependencies
<properties>
<spring.version>4.1.1.RELEASE</spring.version>
<aspectj.version>1.8.2</aspectj.version>
<hibernate.version>4.3.6.Final</hibernate.version>
<druid.version>1.0.9</druid.version>
</properties>
<dependencies>
......
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
......
</dependencies>
Notice that I have added aspectjrt
and aspectjtools
dependencies (version 1.8.2) in the project. Also, I have updated the Spring framework version to be the latest one as of date i.e 4.1.1.RELEASE. You can get this configuration on GitHub.
Spring Bean Configuration with AOP
If you are using Spring Tool Suite, you have the option to create “Spring Bean Configuration File” and chose AOP schema namespace but if you are using some other IDE, you can simply add it to the spring bean configuration file.
<!-- Enable AspectJ style of Spring AOP -->
<aop:aspectj -autoproxy=""></aop:aspectj>
<bean id="viewAspect" class="org.verwandlung.voj.aspect.ViewAspect"></bean>
- Declare AOP namespace like xmlns:aop=”http://www.springframework.org/schema/aop”
- Add aop:aspectj-autoproxy element to enable Spring AspectJ support with auto proxy at runtime
- Configure Aspect classes as other Spring beans
You can see that I have a lot of aspects defined in the spring bean configuration file, it’s time to look into that one by one.
Controller Class
@Controller
@RequestMapping(value = "/")
public class DefaultController {
@RequestMapping(value = "/*", method = RequestMethod.GET)
public ModelAndView indexView(HttpServletRequest request, HttpSession session) {
ModelAndView view = new ModelAndView("index");
return view;
}
}
Before and After Aspect Example
@Aspect
public class ViewAspect {
@Before("execution(* org.verwandlung.voj.controller.*.*View(..))")
public void beforeAspect() {
System.out.println("This method will be invoked before the aspect.");
}
@After("execution(* org.verwandlung.voj.controller.*.*View(..))")
public void afterAspect() {
System.out.println("This method will be invoked after the aspect.");
}
}
Important points in the above aspect class are:
- Aspect classes are required to have
@Aspect
annotation. - @Before annotation is used to create Before advice
- @After annotation is used to create After advice
- beforeAspect() advice will execute for any Spring Bean method with signature
public ModelAndView indexView(any parameters)
. This is a very important point to remember, if we will create Controller bean the advice will not be applied. Only when we will use ApplicationContext to get the bean, advice will be applied.
We will look for advice in action in a test class after we have looked into all the different types of advice.
Around Aspect Example
As explained earlier, we can use Around aspect to cut the method execution before and after. We can use it to control whether the advised method will execute or not. We can also inspect the returned value and change it. This is the most powerful advice and needs to be applied properly.
@Aspect
public class ViewAspect {
@Around("execution(* org.verwandlung.voj.controller.*.*View(..))")
public ModelAndView getUserProfile(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
ModelAndView view = null;
System.out.println("Before invoking getUserProfile() method");
view = (ModelAndView) proceedingJoinPoint.proceed();
System.out.println("After invoking getUserProfile() method");
view.addObject("profile", getUserProfile());
return view;
}
}
Around advice is always required to have ProceedingJoinPoint as an argument and we should use its proceed() method to invoke the target object advised method. If the advised method is returning something, it’s the advice responsibility to return it to the caller program. For void methods, the advice method can return null. Since around advice is cut around the advised method, we can control the input and output of the method as well as its execution behavior.
Passing Parameters to AOP Advice
In Spring AOP it is possible to pass parameters from the intercepted method into the advice.
@Aspect
public class ViewAspect {
@Around(value = "execution(* org.verwandlung.voj.controller.*.*View(..)) && args(.., session)")
public ModelAndView getUserProfile(ProceedingJoinPoint proceedingJoinPoint, HttpSession session) throws Throwable {
ModelAndView view = null;
view = (ModelAndView) proceedingJoinPoint.proceed();
User user = (User) session.getAttribute("user");
view.addObject("profile", user);
return view;
}
}
The advice we just defined will intercept all calls to any Spring bean method defined in the *View method in the controller class. which in turn takes at least a parameter of type HttpSession. The session parameter should be the last parameter (note the args expression).
The Disqus comment system is loading ...
If the message does not appear, please check your Disqus configuration.