In Spring, we have the ability to apply custom annotations to methods, classes, or fields, in order to execute specific actions before or after the annotated object. This is achieved through Aspect-Oriented Programming (AOP).
To implement this solution, we need to create both a custom annotation and a method that will be triggered when the application encounters the annotation. Annotations serve as markers, indicating a specific point in the code, and in order to perform an action, we need to associate that marker with a method from a designated class. Therefore, creating a custom annotation also involves creating an Aspect class/method.
For example, let's consider an annotation that verifies if a person has a particular role. This annotation can be used within methods in a Spring Controller.
Annotation @VerifyAuthorization
To create an annotation, you need to use the syntax below. Please notice:
- Use @interface to define the annotation
- Use @Retention to choose the policy (usually RUNTIME)
- Use @Target to specify the element type (TYPE for class, METHOD, or FIELD)
To create an annotation with parameters, we need to define them as the syntax below.
// define annotation
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface VerifyAuthorization {
String value() default "";
}
// use in a controller method
@RestController
public class ThisController {
@VerifyAuthorization("boss")
public String save () {...}
}
Aspect Method
With Aspect, we can intercept virtually any call in Java. There are two frameworks for this: Spring AOP and AspectJ. While AspectJ is more flexible, it is also more complex.
To intercept the annotation and execute a specific method before (or after or around) the annotated target, we define what is called advice.
Firstly, we need to install spring-boot-starter-aop
if using Spring Boot or AOP
and AspectJ
if using Spring. There is a trick. AspectJ doesn't search targets automatically. So, we need to enable this feature in a XML or annotation format.
After all installations and configurations are completed, we can create a method and link it to the annotation.
Notice in the syntax:
- @Aspect annotation for the aspect class
- @Component to make it unique
- @Before (or @After or @Around) annotation indicating the annotation
- JoinPoint holds the method information
Inside the method, we use some objects to access the annotated method and its parameters.
@Aspect
@Component
public class VerifyAuthorizationAdvice {
@Before("@annotation(com.example.VerifyAuthorization)")
public void beforeAnnotation(JoinPoint joinPoint){
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
VerifyAuthorization annotation = signature.getMethod().getAnnotation(VerifyAuthorization.class);
CustomUserSecurity.hasRole(annotation.value());
}
}
The VerifyAuthorizationAdvice
class can include any necessary logic or dependency. In the example, @Before is used to run the method before the annotated one. If an exception is thrown, the original method will not be executed. Alternativelly, @After could be used to run it after the original method, or @Around to replace it. When using @Around, we can control when the original method is executed by calling joinPoint.proceed();
at some point within our advice method.
Top comments (0)