0% found this document useful (0 votes)
4 views26 pages

Actutor

Uploaded by

Sunil
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views26 pages

Actutor

Uploaded by

Sunil
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 26

Chapter7.

Spring AOP
In this chapter, I will explain AOP, which is the core of Spring as well as DI.

Overview of AOP
Preparation before development
AOP implementation (log output)
Summary

7.1 Overview of AOP


First, let's understand the outline of AOP.

What is AOP?
AOP terminology
Internal workings of AOP

7.1.1 What is AOP?


What is AOP? AOP is an abbreviation for Aspect Oriented Programming. In
a nutshell, it is to extract the processes common to each class and manage
them collectively.

For example, suppose you write a start log and an end log in each class
method. In that case, the code would look like this:

[Sample] Output start log and end log for each method

public void methodA () {


System.out.println("Method A start");
// Method A processing (omitted)
System.out.println("Method A ends");
}

public void methodB () {


System.out.println("Method B start");
// Method B processing (omitted)
System.out.println("Method B ends");
}

The problem here is that it is troublesome to log each method. It is possible


that someone forgets to write the log output. Also, if you change the log
output method to Logback instead of "System.out.println", the amount of
code modification will be very large.

In AOP, these common processes are put together in one place. Then, you
can select which class and which method to apply the common processing.
[Outline of AOP]

In this way, common processing is managed separately. That way, you can
focus on the essential code (the code you should write) when creating each
class. Also, since common processing is omitted, the readability of the code
is improved.

The following are typical common processes that can be managed by AOP.

Log output
Security
Transaction
Exception handling
Cache
Retry

...etc.
In object-oriented, it is difficult to assign a common process to each object.
It is AOP that made it possible.

7.1.2 AOP terminology


Here is a brief introduction to AOP terminology. Understanding AOP
terminology makes it easy to understand how AOP works inside. The terms
of AOP are as follows.

[AOP terminology]
Terminology Description

Advice This is the process executed by AOP.

Pointcut A place (class or method) that executes a process.

JoinPoint It is the timing to execute the process.

JoinPoint (timing) is classified into the following 5 types depending on the


timing at which Advice is executed.

[Join Point (execution timing)]


Timing Description

Before the method is executed, execute AOP processing


Before
(Advice).

After the method is executed, AOP processing (Advice) is


After
executed.

AOP processing (Advice) is executed only when the


AfterReturning
method ends normally.

Before and after executing the method, execute AOP


Around
processing (Advice).
AOP processing (Advice) is executed only when the
AfterThrowing
method terminates abnormally.

These are shown in the figure below.

[Before]

Advice is executed before the method is called.

[After]

Advice is executed after executing the method.


[AfterReturning]

Advice is executed only when the method ends normally.

[Around]

Advice is executed before and after method execution.

[AfterThrowing]
Advice is executed when the method ends abnormally (exception).
7.1.3 Internal workings of AOP
I will explain how it works as an internal mechanism of AOP. If you
understand this, it will be much easier to understand when making.

The mechanism of AOP is very simple. The following describes an example


of calling the method of "LoginController" class.

[Mechanism of AOP]

First, it tries to call the method of the Bean registered in the DI container. In
the above figure, "LoginController" is registered as Bean.

However, it does not call the bean method directly. Proxy is automatically
generated and Bean method is called via Proxy. Then, execute the advice
(AOP processing) before and after calling the bean method.

This is the internal workings of AOP.


7.2 Preparation before development
Let's prepare before making AOP.

Description of development content


Editing pom.xml

*For those who do not have time, you can download the source code at the
end of these preparations from the link at the end of this book. In that case,
please download the folder "SpringStart" in the folder "01. Preparation
point" in Chapter 7. [Click here for links at the end of the book]

7.2.1 Description of development content


First, let's talk about the application we will create in this chapter. In this
chapter, we will output a start log and an end log each time the method of
each controller class is called.

Also, there are various patterns such as Before and After in AOP, so I will
explain how to implement them.

7.2.2 Editing pom.xml


To use AOP, add the following code in the dependencies tag of pom.xml.
The underlined part in red is the additional part.
[Pom.xml] (partial excerpt)

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

(Omitted)

<!-- Spring AOP -->


<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
</dependencies>

After editing "pom.xml", please update Meven.

To update, right-click the project> "Maven"> Select "Update Project".


pom.xml

The preparation is now complete.

7.3 AOP implementation (log output)


Now, let's learn while actually making AOP.

Pointcut (execution location)


Implementation of Before and After
Implementation of Around
Other ways to specify Pointcut

7.3.1 Pointcut (execution location)


Before making it, I will tell you how to specify Pointcut (execution
location) first. That is, how to specify which class the AOP applies to. There
are the following 4 types of designation methods.

[How to specify Pointcut]


Pointcut Description

Specify any class, method, etc. as an AOP target using


execution
regular expressions.

Specify the AOP target with the Bean name registered in the
bean
DI container.

Specify by annotation name.


@annotation The method with the specified annotation will be the target
of AOP.

Specify by annotation name.


@within All methods of the class with the specified annotation are
subject to AOP.

We will actually use these Pointcuts later.

7.3.2 Implementation of Before and After


First, create a package and class for AOP. The directory structure is as
follows. The red underlined part is the part to be newly created this time.
[Directory structure] (partial excerpt)

SpringStart
└ src/main
├ java
│└ com.example.demo Package
│ ├ SpringStartApplication.java
│ ├ WebConfig.java
│ └ login Login processing package
│ ├ aspect AOP package
│ │└ LogAspect.java
│ ├ controller Controller class package
│ └ domain Business logic package
└ resouces
├ static Folder for static files
├ templates Folder for html files
├ application.properties
├ messages.properties
├ messages_en.properties
├ data.sql
└ schema.sql

Edit the LogAspect class as follows.


[7-3-2]com.example.demo.login.aspect.LogAspect.java

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

// Point1 : @Aspect
@Aspect
@Component
public class LogAspect {

// Point 2: AOP implementation


@Before("execution(∗
com.example.demo.login.controller.LoginController.getLogin(..))")
public void startLog(JoinPoint jp) {
System.out.println("Method start: " + jp.getSignature());
}

// Point 2: AOP implementation


@After("execution(∗
com.example.demo.login.controller.LoginController.getLogin(..))")
public void endLog(JoinPoint jp) {
System.out.println("Method end: " + jp.getSignature());
}
}

Point1 : @Aspect

Annotate the AOP class with "@Aspect". At the same time, add
"@Component" annotation to define Bean to DI container. Please
remember to add these two annotations as a set.

Point 2: AOP implementation


Add "@Before" or "@After" annotation to the method that executes AOP.
These are the same names as the JoinPoint (timing) explained earlier.
Then, for the parameter in the annotation, specify the target class and
method. Specify execution as follows.

[How to specify execution]

"execution(<return value> <package name>.<class name>.<method


name>(<argument>)”

Regular expressions can be used for package names and class names.

[How to use regular expressions]

* (Asterisk)
Use an asterisk to represent any character string. One asterisk
represents one level of package. One asterisk, one argument in the
method.

.. (Two dots)
If you write two dots in a row, the package description indicates any
(0 or more) package. In the method argument, it represents an
arbitrary (0 or more) argument.

+ (Plus)
A Plus after the class name includes subclasses of the specified class.

In the sample code, the "getLogin" method of "LoginController" class is


set to Pointcut (execution location).

[Execution]
After creating it, launch Spring Boot and access the login screen. Then, the
following log is output to the console.
Method start: String
com.example.demo.login.controller.LoginController.getLogin(Model)
Method end: String
com.example.demo.login.controller.LoginController.getLogin(Model)

Now every time the LoginController's getLogin method is called, a log will
be output. Of course, if this is the case, no log will be output even if the
method of another controller class is called.

Next, we will try to make it a little more general. Change the argument in
@Before and @After annotation as follows. The underlined part in red is the
changed part.
[7-3-2]com.example.demo.login.aspect.LogAspect.java

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogAspect {

// Point: Target all methods of controller class


@Before("execution(∗ ∗..∗.∗Controller.∗(..))")
public void startLog(JoinPoint jp) {
System.out.println("Method start: " + jp.getSignature());
}

// Point: Target all methods of controller class


@After("execution(∗ ∗..∗.∗Controller.∗(..))")
public void endLog(JoinPoint jp) {
System.out.println("Method end: " + jp.getSignature());
}
}

Point: Target all methods of controller class

In the above Pointcut (execution location), if "Controller" is added to the


end of the class name, all methods of that class are subject to AOP.

[How to specify execution]

execution(<return value> <package name>.<class name>.<method


name>(<argument>)”
Return value
∗ (asterisk) specifies all return values.

Package name
Specify "*..*" to target all packages.

Class name
By specifying "∗Controller", the class with "Controller" at the end of
the class name will be the target.

Method name
∗ (asterisk) applies to all methods.

Argument
.. (two dots) to target all arguments.

[Execution]
After creating it, start Spring Boot and try to access the login screen and
user registration screen. Then, the start/end logs of all the methods of the
controller class are output to the console (the execution results are omitted).

7.3.3 Implementation of Around


Since "Around" is a little special among JoinPoints, let's actually make it
and check it. Modify the "LogAspect" class created earlier as follows.
[7-3-3]com.example.demo.login.aspect.LogAspect.java

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogAspect {

// Point 1: @Around
@Around("execution(∗ ∗..∗.∗Controller.∗(..))")
public Object startLog(ProceedingJoinPoint jp) throws Throwable {

System.out.println("Method start: " + jp.getSignature());

try {
// Point 2: Method execution
Object result = jp.proceed();

System.out.println("Method end: " + jp.getSignature());

return result;

} catch (Exception e) {
System.out.println("Method abnormal termination:
" + jp.getSignature());
e.printStackTrace();
throw e;
}
}
}

Point 1: @Around
When using "Around" at JoinPoint (execution timing), use "@Around"
annotation.

Point 2: Method execution

When "Around" is used, the method of AOP target class is directly


executed in the annotated method. Executing with the proceed method.

So, using "Around", you can do arbitrary processing before and after the
method execution. Since the method is executed directly, specify the
return value of the execution result in the return statement.

Please note that it is difficult to forget to execute the method in Around.


[Execution]
After creating it, start Spring Boot and try to access the login screen and
user registration screen. Then, the start/end logs of all the methods of the
controller class are output to the console.

Method start: String


com.example.demo.login.controller.LoginController.getLogin(Model)
Method end: String
com.example.demo.login.controller.LoginController.getLogin(Model)

Now you know how to use Before/After/Around. "After Returning" is


omitted because it has the same usage as "After".

You will learn about "After Throwing" in [Chapter 9 Exception Handling].


7.3.4 Other ways to specify Pointcut
Let's look at other ways to specify Pointcut. Here, we will introduce 3
methods.
*You can just look at it without actually making it.

1. Method to specify by Bean name


2. How to specify a method with annotations
3. How to specify all methods of the annotated class

First, let's see how to specify the target of AOP by Bean name.
[7-3-4]com.example.demo.login.aspect.LogAspect.java

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogAspect {

// Specified by Bean name


@Around("bean(∗Controller)")
public Object startLog(ProceedingJoinPoint jp) throws Throwable {
// Omitted
}
}

Point: Specified by Bean name

If you write "bean" in Pointcut, you can specify the target of AOP with
the Bean name registered in DI. Of course, you can also use regular
expressions.

[How to specify a bean]

bean (<Bean name>)

Next, I will explain how to specify a method with an arbitrary annotation.


[7-3-4]com.example.demo.login.aspect.LogAspect.java

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogAspect {

// Point:@annotation

@Around("@annotation(org.springframework.web.bind.annotation.GetM
apping)")
public Object startLog(ProceedingJoinPoint jp) throws Throwable {
// Omitted
}
}

Point:@annotation

Use "@annotation" to target all methods with the specified annotation. In


that case, specify the class name including the package name.

Next, we will create it by specifying all the methods of the annotated class.
[7-3-4]com.example.demo.login.aspect.LogAspect.java

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogAspect {

// Point: @within
@Around("@within(org.springframework.stereotype.Controller)")
public Object startLog(ProceedingJoinPoint jp) throws Throwable {
// Omitted
}
}

Point: @within

If you use "@within", all methods of the class with the specified
annotation will be targeted. Again, specify the class name including the
package name.

This concludes AOP learning.


7.4 Summary
AOP is a mechanism that allows you to manage common processes
collectively. The lessons learned in this chapter are:

[AOP terminology]

Advice: Processing content


Pointcut: Execution location
JoinPoint: Execution timing

[How to make AOP]

Add "@Aspect" and "@Component" annotations to AOP classes.


Annotate JoinPoint to the method of AOP class.
Specify Pointcut in the annotation of JoinPoint.

[How to specify Join Point]

Add the following JoinPoint annotation to the AOP class method.


1. @Before: before execution
2. @After: After execution (normal end/above end)
3. @Around: Before and after execution
4. @AfterReturning: After normal end
5. @AfterThrowing: After abnormal termination

[How to specify Pointcut]

Specify the following Pointcut in the annotation of JoinPoint.


1. execution (<Return value> <Package name>.<Class name>.
<Method name> (<Argument>)
2. bean (<Bean name>)
3. @annotation(<Package name>.<Annotation name>)
4. @within(<Package name>.<Annotation name>)

You might also like