We are using Application Insights to monitor different service calls in our applications. Data for Application Insights is provided by many different methods and classes but always in an identical way/by identical code fragments:
public class MyClassA { public void myMethodA() { final Instant startTime = Instant.now(); try { callSomeServiceA(); } catch (final Exception e) { sendExceptionDataToAppInsights(e); throw e; } finally { sendDataToAppInsights(MyClass.getName(), myMethodA.getName(), startTime, Instant.now()); } } } public class MyClassB { public String myMethodB() { final Instant startTime = Instant.now(); try { return callSomeServiceB(); } catch (final Exception e) { sendExceptionDataToAppInsights(e); throw e; } finally { sendDataToAppInsights(MyClass.getName(), myMethodA.getName(), startTime, Instant.now()); } } }
How am I able to extract those wrapping try catch fragments to one point of responsibility? I took a look at the dacorator pattern but I guess it doesn’t fit because of the different method signatures. Or does it?
Or is there a way to achieve it with AOP?
Advertisement
Answer
Aspect-Oriented Programming is the paradigm to modularize cross-cutting concerns such as logging, monitoring and error handling (your particular case).
The most popular framework to achieve this in Java is AspectJ, which can be used from any Spring project via the spring-boot-starter-aop
dependency.
Maven
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> <version>${aop-version}</version> </dependency>
Gradle
implementation `org.springframework.boot:spring-boot-starter-aop:${aop-version}`
The simplest way to achieve what you’re asking is to make an aspect (using @Aspect
) that uses @Around
. There are plenty of examples of this online. Your execution (ProceedingJoinPoint
:: proceed
) will need to happen inside a try-catch block very similar to what you have in your question:
@Around("execution(<aspectj-selector-here>)") public void anyMethodName(ProceedingJoinPoint pjp) { // try-catch blocks here... }