This time, I would like to write about Spring AOP. If you want to know the detailed specifications, please read Official Reference. The version is Spring Boot 2.0.1.RELEASE (Spring 5.0.5.RELEASE).
AOP stands for ** Aspect Oriented Programming ** and is called "Aspect Oriented Programming". In AOP, write code to separate cross-class processing (exception handling, logging, transaction processing, etc.) from the business logic. This makes it possible to simply write multiple processes and prevent code that performs the same process from being written in various places.
Aspect Aspect is a module that defines cross-cutting processing and where to perform it. In Spring, by adding @Aspect to a class, that class will be recognized as Aspect. You need to define Aspect as a bean, so don't forget to declare it as a bean with @Component. (@Service and @Repository where @Component is declared internally are also OK.)
@Component
@Aspect
public class HogeAspect{
}
JoinPoint JoinPoint refers to the place (method) where the cross-cutting process is inserted. PointCut PointCut is a representation of a collection of JoinPoints. As shown in the code example below, PointCut is expressed as an annotation parameter of Advice (described later). In the example of ↓, JoinPoint is specified by execution ().
@After(value = "execution(* com.example.fuga..Fuga.*(..))")
public void Hoge(/* .. */){
/* .. */
}
/*In Spring, if there are no other parameters, the parameter named value "value"=Can be omitted, so
@After("execution(* com.example.fuga..Fuga.*(..))")You can also write.*/
In execution (), JoinPoint is expressed by the following grammar.
execution(Return value Package name.name of the class.Method name(Argument type))
/*
「*」 ->Represents an arbitrary character string. However, when used as a package name, it represents "one package with an arbitrary name", and when used as an argument, it represents "one arbitrary type".
「..」 ->When used as a package name, it represents "a package of 0 or more", and when used as an argument, it represents "any type of 0 or more".
*/
In the first example, it is expressed that @After is applied to all methods of the class "Fuga" under the "com.example.fuga" package (including subpackages) with an arbitrary return value. doing.
Besides execution (), there are various things such as within () and this (), but execution () is often used. Reference
Advice Advice represents the cross-cutting process itself performed by JoinPoint. By annotating the method of the class with @Aspect, that method can be executed as Advice. There are five types of annotations that represent Advice: @Before Advice that is executed before processing the target method.
@Before("execution(* *..*(..))")
public void beforeHandler(){
/* .. */
}
@After Advice that is always executed regardless of the processing result of the target method.
@After("execution(* *..*(..))")
public void afterHandler(){
/* .. */
}
@AfterReturning Advice that is executed only when the processing of the target method is completed correctly. If you specify a character string in the returning parameter, the return value of the process executed by JoinPoint is stored in the variable of that character string. This allows the return value to be used in Advice.
@AfterReturning(value = "execution(* *..*(..))", returning = "r")
public void afterReturning(Object r){
System.out.println(r);
}
@AfterThrowing Advice that is executed only when an exception occurs while processing the target method. If you specify a string in the throwing parameter, the variable in that string will contain the exception that occurred in the process executed by JoinPoint. This allows exceptions to be used in Advice.
@AfterThrowing(value = "execution(* *..*(..))", throwing = "e")
public void afterThrowing(Throwable e){
System.out.println(e.getMessage());
}
@Arround Advice that can be executed at any time before or after processing the target method. As shown in the example below, pre-processing and post-processing can be set freely.
@Arround("execution(* *..*(..))")
public void arround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("Preprocessing")
//Method execution
Object result = pjp.proceed();
System.out.println("Post-processing")
}
If you are using Spring Boot, add "spring-boot-starter-aop" to the dependencies of pom.xml. If "spring-boot-starter-parent" is specified as parent, it is not necessary to specify the version of spring-boot-starter-aop because the version information has already been defined.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
If you are not using Spring Boot, you can use it by adding "spring-aop" and "aspectjweaver" to pom.xml and adding @EnableAspectJAutoProxy to JavaConfig (operation unconfirmed).
Create a class for Aspect and prefix the class with @Aspect and @Component.
@Component
@Aspect
public class HogeAspect{
}
Create a method in the class defined as Aspect. Annotate the Advice described above as appropriate according to the timing of executing the Advice. In addition, use execution () to describe in which class or method the created Advice is applied in the Advice annotation.
@Component
@Aspect
public class HogeAspect{
@AfterThrowing(value = "execution(* *..*(..))", throwing = "ex")
public void handler(Throwable ex){
/* .. */
}
}
In the example above, exception handling is defined for exceptions that occur in all methods.
https://docs.spring.io/spring/docs/5.0.5.RELEASE/spring-framework-reference/core.html#aop
Recommended Posts