TechnologyMay 03, 2016

Aspect-Oriented Programming in Spring Boot Part 1: Making Your Own Hystrix Aspect

Justin Wilson

This is the first entry in a three-part series covering aspect-oriented programming (AOP) in Spring Boot using Spring proxies (with and without CGLIB) and AspectJ load-time weaving (LTW). A sample project that uses all three methodologies can be found here at GitHub. This entry covers the basics of AOP.

What Is Aspect-Oriented Programming?

Aspect-oriented programming compliments object-oriented programming by allowing cross-cutting concerns (such as security, logging, and database transaction management) to be “woven” into existing code without needing to explicitly call it. Code written once can be applied to many similar locations (or “join points”) that share common traits.

For example, when you use @Transactional on a method in a Spring bean, callers of that bean can automatically wrap the execution of that method inside a database transaction without writing any extra code. Spring “weaves” that functionality in before the annotated method is invoked and after it’s done executing. The alternative would be manually invoking a TransactionTemplate within every service method that needed a database transaction, which would add a lot of boilerplate code

For example, you can turn this:

@Autowired PlatformTransactionManager platformTransactionManager;   public void methodName() { TransactionTemplate template = new TransactionTemplate(platformTransactionManager); template.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { // business logic } });}

Into this, using the power of AOP:

@Transactional public void methodName() { // business logic}

Where Does the Woven Code Come From?

Woven code comes from aspects. To demonstrate their inner workings, let’s make our own aspect that uses Netflix’s Hystrix to wrap a method in a new thread.

Hystrix Primer

Hystrix is a circuit breaking library that’s used to wrap arbitrary code in a new thread while blocking the calling thread (or letting the caller register an observable). If the wrapped code takes too long to execute or has been failing too frequently, Hystrix will tell the caller to give up and continue without the wrapped code’s results. This frees the caller’s threads from getting tied up due to waiting on an unresponsive piece of code (usually due to network issues or unresponsive external services), mitigating how many systems are affected by one slow dependency.

For example, if wrapped code makes a network call that hangs for two minutes and you can’t easily control that code’s network timeout settings, you might want to regain control of your thread after ten seconds instead of tying up your resources. Additionally, if a lot of calls to the same wrapped code have failed recently, Hystrix can “break a circuit” (an analogy to electric systems) and make all future calls to that method immediately fail on the assumption that a network dependency is unavailable, until enough time has passed to try enabling the circuit again.

For more information, see the official Hystrix wiki. For our purposes, we only care about causing methods to be invoked on separate threads. We’ll compare the thread ID of the calling thread to the thread ID of code wrapped in Hystrix via AOP to validate that our Hystrix aspect was woven correctly.

Here’s an example of how we could wrap code in Hystrix manually:

HystrixCommand<object width="300" height="150"> command = new HystrixCommand<object>(HystrixCommandGroupKey.Factory.asKey(“myCommandGroupKey”)) {@Overrideprotected Object run() throws Exception { return Thread.currentThread().getId()}};command.execute();

We only have to create a new HystrixCommand object and pass it the code we want to run in a new thread inside its anonymous inner function. Then we tell the command to execute, which will run the code inside the “run” method. HystrixCommand objects can only execute once, so a new one is made every time this code is called. The “Command Group Key” argument is required by Hystrix and can be combined with optional Java properties to determine the size of the thread pool allocated to all commands that share that particular group key value, as per Hystrix’s documentation. Now let’s extract that HystrixCommand code into an aspect so we won’t have to write all that wrapper code manually every time we want to use it!<strong>Annotation Join Point</strong>The goal is to be able to wrap a method in a custom-made annotation called @HystrixWrapper. The annotation itself is actually very simple—we need to retain it at runtime to be able to see which methods use it, and we only want it to be placed on methods. Because all HystrixCommands require a command group key, we’ll make that a required field when the annotation is applied to a method. The class below can also be seen on GitHub.

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface HystrixWrapper { public String commandGroupKey();}

The annotation itself doesn’t do anything—we just want to put it on the methods where we want to inject code to become a “join point” to target. For example, consider this method:

@HystrixWrapper(commandGroupKey = "blog")public long hystrixWrappedGetCurrentThreadId() { return getCurrentThreadId();}

When AOP is properly enabled, calls to this method will return a different thread ID than the calling thread. But where does the actual HystrixCommand code come from?Custom Aspect We need to create an @Aspect class and tell it to run “around” any method annotated with @HystrixWrapper. We can qualify that we only care about the @HystrixWrapper annotation if it’s present on classes in certain packages to slightly improve performance, and we can annotate the aspect with @Component to allow Spring beans to be injected inside it with the @Autowired annotation for additional functionality. The @Component annotation is completely optional; @Aspect is all Spring’s component scanner needs to see to register the aspect for potential weaving. A more detailed version of the HystrixAspect class below can be found here at GitHub.

@Aspect@Componentpublic class HystrixAspect {@Around("within(*) &amp;&amp; " "@annotation(")public Object around(final ProceedingJoinPoint joinPoint) { Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); HystrixWrapper annotation = method.getAnnotation(HystrixWrapper.class); String commandGroupKey = annotation.commandGroupKey(); // Continue execution in a new Hystrix thread HystrixCommand<object> command = new HystrixCommand<object>( HystrixCommandGroupKey.Factory.asKey(commandGroupKey)) { @Override protected Object run() throws Exception { try { return joinPoint.proceed(); } catch (Exception e) { throw e; } catch (Throwable e) { throw new RuntimeException(e); } } }; return command.execute(); }}

The important parts of the aspect have been highlighted. By annotating the class with @Aspect, we can inform Spring that this class contains methods eligible for weaving. The @Around annotation indicates that the following code should be run instead of any method annotated with @HystrixWrapper in the package (or any of its subpackages using the “..*” wildcard).

Finally, the ProceedingJoinPoint argument lets us continue executing the original method that was annotated with @HystrixWrapper. By creating a HystrixCommand object and only letting the joinPoint argument proceed when that command object is executed, we can wrap the original method’s execution within a Hystrix thread. If we didn’t call joinPoint.proceed(), we would completely replace the behavior of the original method with the contents of the aspect.

In addition to @Around, you can also tell an @Aspect to only run @Before, @After, @AfterReturning (to use a returned value), or @AfterThrowing (to use a thrown exception). This series will only cover @Around, but other examples can be found here.

The last step we’ll need to do is import spring-boot-starter-aop (mvnrepository link) and hystrix-core (mvnrepository link) as dependencies in a build.gradle or pom.xml file. The sample project uses Gradle, as seen here.

Note that even though the @Aspect and @Around annotations come from the org.aspectj package, we’re not actually using real AspectJ yet; we’re just hijacking its classes to define aspects for Spring’s own version of AOP. The differences between Spring AOP and AspectJ will be covered in part two.

Next Steps

That’s it for creating our own aspect. Spring Boot will be able to weave this aspect out of the box with its default settings. However, with those default settings, Spring will only invoke the aspect if the annotated method was exposed on Spring bean and called from another Spring bean.

Depending on whether or not the bean being invoked has an interface, the aspect might not run correctly without enabling CGLIB. If we want the aspect to run all the time no matter where the annotated method is called from, we’ll need to set up AspectJ which requires a little more configuration. For all these answers and more, stay tuned for the next two entries in this series by following @CrederaOpen on Twitter or connecting with us on LinkedIn.