AOP with Spring

Our Spring Boot Web Application is starting making sense. As we have seen in the previous post, the controller is wired to a bean, a Knight, that is wired to another bean, a Quest. When the URI /quest is accessed, the RESTful service's nature of the controller enters in the game and, following all the wiring down to the bottom, what the caller gets is the message generated by the embark() method of the actual Quest objected involved.

Now we want to introduce a class that follows a different perspective, a Minstrel whose raison d'ĂȘtre is singing when a Knight starts and ends a Quest. It's behavior is orthogonal to "normal" way we look at our code. We think at what a minstrel is interested in, we let it know to Spring, and just rely on it. In Aspect Oriented Programming (AOP) terms, Mistrel becomes an aspect of our application.

The nice point in AOP is that only the aspect, here Minstrel, has to know about what is going on. Knight could stay in its blissful ignorance on the matter, performing its mission as nothing as changed. Here I have changed the concrete Knight implementation just to add a line of log in its doQuest() method, that would help us in seeing the system at work. I have written more on Spring log in another post.

To use AOP in Spring Boot, you have to add a dependency in your application POM file. STS helps you not to forget it, anyway, groupId is org.springframework.boot and artifactId spring-boot-starter-aop. Besides, I should give to Spring some way to know which aspects it has to work with. We can do it through a XML file or a Java class configuration AspectJ style. I prefer the second way.

So I created a SpringInActionConfig class where I specified the bean that is actually an aspect:
@Configuration
@EnableAspectJAutoProxy
public class SpringInActionConfig {
    @Bean
    public Minstrel minstrel() {
        return new Minstrel();
    }
}
Notice the two annotations on the class and the bean annotation on its method that just creates a new Minstrel and returns it.

I have implemented Minstrel in this way, again using the Spring AspectJ support:
@Aspect
public class Minstrel {
    private final Log log = LogFactory.getLog(Minstrel.class);

    @Before("execution(public String Knight.doQuest())")
    public void singBeforeQuest() {
        log.info("Fa la la, the knight is so brave!");
    }

    @After("execution(public String Knight.doQuest())")
    public void singAfterQuest() {
        log.info("Tee hee hee, the brave knight did embark on a quest!");
    }
}
The class is annotated as Aspect, and it has two annotated method, one that has to be executed before the Knight doQuest() method, the other after.
Notice the AspectJ sintax. It looked a bit weird to me the first time, however it makes sense. I have used a very plain and comprehensible notation, it could get much more cryptic. On the other side, it is quite powerful.

Now, when we run our application we should not see any change in its behavior, but in its log, that now should have in it something like that:

I have written this post while reading the first chapter of Spring in Action, Fourth Edition by Craig Walls. I have ported the original code to a Maven Spring Boot Web project on the STS IDE, using AspectJ annotations instead of the classic xml configuration.

Full code on github.

No comments:

Post a Comment