Let’s assume we have to pass some parameters to the aspect that intercept method invocations. It may be for example the level of logging (DEBUG, INFO, WARNING and so on), format (plain text, JSON, XML), name of the web service.
@LogIt(level = INFO)
or
@LogThis(format = JSON)
or
@LogThat(service = BOOK_SERVICE)
Let’s implement one of them - @LogThat
.
We’re going to modify our solution in Logging service client calls with AspectJ
Log annotation with parameters
First we need to add a parameter Service service
to our annotation
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogThat {
Service service();
}
public enum Service {
BOOK_SERVICE("BOOK SERVICE"),
CUSTOMER_SERVICE("CUSTOMER SERVICE"),
INVENTORY_SERVICE("INVENTORY SERVICE");
public String name;
Service(String name) {
this.name = name;
}
}
Doing that we don’t need to have separate annotations like @LogBookService, @LogCustomerService and @LogInventoryService for each service anymore. We just pass a service as a parameter.
Accessing annotation parameters
Now we can access that parameter from an aspect just like this
((MethodSignature) jp.getSignature()).getMethod().getAnnotation(LogThat.class).service()
Logger aspect
Finally in our ServiceLogger aspect we have one @Around
for all services
@Aspect
@Component
public class ServiceLogger {
private Gson gson = new GsonBuilder().setPrettyPrinting().create();
@Around("execution(* *(..)) && @annotation(io.lenar.examples.spring.clients.log.LogThat)")
public Object logServiceMethods(ProceedingJoinPoint jp) throws Throwable {
String methodName = jp.getSignature().getName();
logRequest(jp);
long startTime = new Date().getTime();
Object result = jp.proceed(jp.getArgs());
long endTime = new Date().getTime();
Reporter.log("\nResponse time: " + (endTime - startTime) + "ms", true);
Reporter.log("<- " + methodName + " Response: \n" + gson.toJson(result) + "\n", true);
return result;
}
private void logRequest(ProceedingJoinPoint jp) {
String serviceName = ((MethodSignature) jp.getSignature()).getMethod()
.getAnnotation(LogThat.class).service();
Reporter.log(serviceName + " CALL:", true);
String[] argNames = ((MethodSignature) jp.getSignature()).getParameterNames();
Object[] values = jp.getArgs();
Map<String, Object> params = new HashMap<>();
if (argNames.length != 0) {
for (int i = 0; i < argNames.length; i++) {
params.put(argNames[i], values[i]);
}
}
Reporter.log("-> " + jp.getSignature().getName() + " Request", true);
if (!params.isEmpty()) Reporter.log(gson.toJson(params), true);
}
}
Aspect weaving
The last thing we need to setup is pom.xml
to properly weave our aspects.
There are some differences between Spring and non-Spring projects so carefully read this - Aspect weaving in Spring and non-Spring projects
You may also find these posts interesting: