In this post, I am going to show how to decorate a method using @Around advice.
Step 1: Define @Around advice.
@Documented
@Retention(RUNTIME)
@Target({ TYPE, METHOD })
@Around
public @interface LogAdvice {
}
a. The retention policy of the annotation should be RUNTIME
b. In General, we apply advice at the class or method level so the target types are TYPE and METHOD
c. @Around annotation is added to tell Micronaut that the annotation is Around advice
Step 2: Implement a method interceptor.
@Singleton
@InterceptorBean(LogAdvice.class)
public class LogInterceptor implements MethodInterceptor<Object, Object> {
@Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
String methodName = context.getMethodName();
System.out.println(methodName + " method called with below arguments");
Set<Entry<String, MutableArgumentValue<?>>> entrySet = context.getParameters().entrySet();
for (Entry<String, MutableArgumentValue<?>> entry : entrySet) {
MutableArgumentValue<?> argumentValue = entry.getValue();
System.out.println("\t" + entry.getKey() + " -> " + argumentValue.getValue());
}
return context.proceed();
}
}
a. The @InterceptorBean annotation specify the the annotation the interceptor is associated with. Note that @InterceptorBean is meta-annotated with a default scope of @Singleton therefore if you want a new interceptor created and associated with each intercepted bean you should annotate the interceptor with @Prototype.
b. ‘context.proceed()’ is called to proceed with the method invocation.
Step 3: Apply the LogAdvice annotation on the method definition.
@Singleton
public class ArithmeticUtil {
@LogAdvice
public Integer add(int a, int b) {
return a + b;
}
}
Whenever the type ArithmeticUtil bean is injected into a class, a compile-time-generated proxy is injected that decorates method calls with the @LogAdvice defined earlier.
Find the below working application.
Step 1: Create new maven project ‘micronaut-around-advice’.
Step 2: Update pom.xml with maven dependencies.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sample.app</groupId>
<artifactId>micronaut-around-advice</artifactId>
<version>0.1</version>
<packaging>jar</packaging>
<parent>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-parent</artifactId>
<version>3.7.3</version>
</parent>
<properties>
<packaging>jar</packaging>
<jdk.version>11</jdk.version>
<release.version>11</release.version>
<micronaut.version>3.7.3</micronaut.version>
<micronaut.runtime>netty</micronaut.runtime>
<exec.mainClass>com.sample.app.App</exec.mainClass>
</properties>
<repositories>
<repository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-inject</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-validation</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-http-client</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-http-server-netty</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-jackson-databind</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.micronaut.test</groupId>
<artifactId>micronaut-test-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>io.micronaut.build</groupId>
<artifactId>micronaut-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<!-- Uncomment to enable incremental compilation -->
<!-- <useIncrementalCompilation>false</useIncrementalCompilation> -->
<annotationProcessorPaths
combine.children="append">
<path>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-http-validation</artifactId>
<version>${micronaut.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
Step 3: Define LogAdvice class.
LogAdvice.java
package com.sample.app.advices;
import io.micronaut.aop.Around;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Documented
@Retention(RUNTIME)
@Target({ TYPE, METHOD })
@Around
public @interface LogAdvice {
}
Step 4: Define LogInterceptor class.
LogInterceptor.java
package com.sample.app.interceptor;
import java.util.Map.Entry;
import java.util.Set;
import com.sample.app.advices.LogAdvice;
import io.micronaut.aop.InterceptorBean;
import io.micronaut.aop.MethodInterceptor;
import io.micronaut.aop.MethodInvocationContext;
import io.micronaut.core.type.MutableArgumentValue;
import jakarta.inject.Singleton;
@Singleton
@InterceptorBean(LogAdvice.class)
public class LogInterceptor implements MethodInterceptor<Object, Object> {
@Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
String methodName = context.getMethodName();
System.out.println(methodName + " method called with below arguments");
Set<Entry<String, MutableArgumentValue<?>>> entrySet = context.getParameters().entrySet();
for (Entry<String, MutableArgumentValue<?>> entry : entrySet) {
MutableArgumentValue<?> argumentValue = entry.getValue();
System.out.println("\t" + entry.getKey() + " -> " + argumentValue.getValue());
}
return context.proceed();
}
}
Step 5: Define ArithmeticUtil class.
ArithmeticUtil.java
package com.sample.app.components;
import com.sample.app.advices.LogAdvice;
import jakarta.inject.Singleton;
@Singleton
public class ArithmeticUtil {
@LogAdvice
public Integer add(int a, int b) {
return a + b;
}
}
Step 6: Define main application class.
App.java
package com.sample.app;
import com.sample.app.components.ArithmeticUtil;
import io.micronaut.context.ApplicationContext;
public class App {
public static void main(String[] args) {
try (ApplicationContext applicationContext = ApplicationContext.run()) {
ArithmeticUtil arithmeticUtil = applicationContext.getBean(ArithmeticUtil.class);
arithmeticUtil.add(10, 20);
}
}
}
Total project structure looks like below.
Build the project using mvn package command.
Navigate to the folder where pom.xml is located and execute the command ‘mvn package’.
Upon command successful execution, you can see the jar file ‘micronaut-around-advice-0.1.jar’ in project target folder.
$ls ./target/
classes
generated-sources
generated-test-sources
maven-archiver
maven-status
micronaut-around-advice-0.1.jar
original-micronaut-around-advice-0.1.jar
test-classes
Execute below command to run the application.
java -jar ./target/micronaut-around-advice-0.1.jar
You will see below messages in the console.
add method called with below arguments a -> 10 b -> 20
You can download the application from this link.
Previous Next Home
No comments:
Post a Comment