1. What is AOP?
AOP is the abbreviation of Aspect Oriented Programming, which means: section-oriented Programming. It is a technology that realizes unified maintenance of program functions through pre-compilation and runtime dynamic proxy.
AOP can be considered as a supplement to OOP(Object Oriented Programming object-oriented Programming), mainly used in logging, performance statistics, security control and other scenarios, using AOP can make the coupling degree between each part of the business logic reduced, only focus on their respective business logic implementation, Thus improve the readability and maintainability of the program.
For example, we need to record all the external interface in the project in and out, so that to locate the problems of reason, in each of the external interface code to add the record into the ginseng and out, of course, also can achieve a goal, but this way of hard-coded very not friendly, is not flexible, and logging itself doesn’t have anything to do with the interface to realize the core functions of.
At this point, we can define the logging capability into one aspect, and then declaratively define when and where to use the aspect without changing any one of the external interfaces.
Before going into the specifics, let’s take a look at a few AOP terms.
1.1 notice (Advice)
In AOP terminology, the work an aspect does is called an advice, and an advice defines what an aspect is and when to use it.
The Spring aspect has five types of notifications, which are:
- Before: Call notification Before the target method is called
- After notification: Call the notification After the target method completes, without caring what the output of the method is
- Post-returning Notification: Notification is called After successful execution of the target method
- After-throwing: Calls notifications After the target method throws an exception
- Around advice: Advice wraps the notified method, performing custom behavior before and after the notified method invocation
1.2 Join Points
A join point is a point at which an aspect can be inserted during application execution, either when a method is called, when an exception is thrown, or when a field is modified.
1.3 point of tangency (Pointcut)
Pointcuts are meant to narrow down the range of join points notified by the cut, that is, where the cut is executed. We usually specify pointcuts using explicit class and method names, or regular expressions that define matching class and method names.
Section 1.4 (Aspect)
A section is a combination of notification and pointcut. Together, advice and pointcuts define what an aspect is all about: what it is, when and where it performs its function.
1.5 introduced (the Introduction)
Imports allow us to add new methods or attributes to existing classes without modifying them.
1.6 woven into (has)
Weaving is the process of applying a facet to a target object and creating a new proxy object.
Sections are woven into the target object at the specified join point. During the life of the target object, the following points can be woven:
- Compile time: The aspect is woven in when the target class is compiled. This approach requires a special compiler. AspectJ’s weaving compiler weaves facets in this way.
- Class loading time: The aspect is woven when the target class is loaded into the JVM. This approach requires special classloaders that enhance the bytecode of the target class before it is introduced into the application.
- Run-time: Facets are woven in at some point during the application run. Typically, the AOP container dynamically creates a proxy object for the target object when weaving into the cut. Spring AOP is woven into the facets in this way.
Spring’s support for AOP
2.1 Dynamic Proxy
Spring AOP is built on dynamic proxies, that is, the Spring runtime dynamically creates proxy objects for target objects.
The proxy class encapsulates the target class, intercepts the invocation of the notified method, and forwards the invocation to the actual target bean.
When a proxy class intercepts a method call, the aspect logic is performed before calling the target bean method.
2.2 Weaving time in section
Spring weaves the aspects into spring-managed beans at run time by wrapping them in proxy classes, that is, Spring does not create proxy objects until the proxied beans are needed by the application.
Because the Spring runtime creates proxy objects, we don’t need a special compiler to weave into the Spring AOP aspect.
2.3 Connection point restrictions
Spring only supports method-level join points, and if field-level or constructor-level join points are needed, AspectJ can complement Spring AOP’s capabilities.
3. Use Spring AOP
Suppose we have a live Performance interface called Performance and its implementation class SleepNoMore:
package chapter04.concert;
/** * Live performances, such as stage plays, films, concerts */
public interface Performance {
void perform(a);
}
Copy the code
package chapter04.concert;
import org.springframework.stereotype.Component;
/** * drama: Sleep No More */
@Component
public class SleepNoMore implements Performance {
@Override
public void perform(a) {
System.out.println("Play" Sleep No More."); }}Copy the code
Since it is a performance, we need an audience. Suppose our needs are: Perform () : People sit down and silence their phones before a performance and clap after it. If they fail, we may write this logic in the perform() method, but we don’t recommend it because it has nothing to do with the core of the performance. Even if the audience does not mute their mobile phones or do not clap after the performance, it does not affect the performance.
For this requirement, we can use AOP to implement it.
3.1 Define the section
First, add the following dependencies to the POM.xml file:
<! Spring AOP support -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.8. RELEASE</version>
</dependency>
<! -- aspectj support - >
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.5</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
Copy the code
Then, define an audience slice as follows:
package chapter04.concert;
import org.aspectj.lang.annotation.Aspect;
/** * audience * use@AspectAnnotations are defined as facets */
@Aspect
public class Audience {}Copy the code
Note: the @aspect annotation indicates that the Audience class is an Aspect.
3.2 Defining pre-notification
In the Audience section, the pre-notification is defined as follows:
Before the performance, the audience took their seats
@Before("execution(* chapter04.concert.Performance.perform(..) )")
public void takeSeats(a) {
System.out.println("Taking seats");
}
/** * Before the performance, put your mobile phone on silent */
@Before("execution(* chapter04.concert.Performance.perform(..) )")
public void silenceCellPhones(a) {
System.out.println("Silencing cell phones");
}
Copy the code
The key here code is @ Before (” execution (* chapter04. Concert. The Performance. The perform (..) ) “), which defines a pre notice, including execution (* chapter04. Concert. The Performance. The perform (..) ) are called AspectJ pointcut expressions, and each section is explained as follows:
- @before: This annotation is used to define a pre-notification that the notification method is executed Before the target method is called
- Execution: Triggered when a method is executed
- * : indicates that we do not care about the type of the method return value, that is, it can be any type
- Chapter04. Concert. The Performance. The perform: use the fully qualified class name and method name specified to add pre warning method
- (..) : Method argument list uses (..) , indicating that we don’t care what the method’s input is, that it can be of any type, right
3.3 Defining post-notification
The post-notification is defined in the Audience section as follows:
/** * The show ends, whether the show succeeds or fails */
@After("execution(* chapter04.concert.Performance.perform(..) )")
public void finish(a) {
System.out.println("perform finish");
}
Copy the code
Note: The @After annotation is used to define a post-notification method that is called After the target method returns or throws an exception
3.4 Define return notification
In the Audience section, define the return notification as follows:
/** * clap */ after the performance
@AfterReturning("execution(* chapter04.concert.Performance.perform(..) )")
public void applause(a) {
System.out.println("CLAP CLAP CLAP!!!");
}
Copy the code
Note: The @AfterRETURNING annotation is used to define return notifications that will be called after the target method returns
3.5 Defining exception notification
Define the exception notification in the Audience section as follows:
/** * After the performance failed, the audience demanded a refund */
@AfterThrowing("execution(* chapter04.concert.Performance.perform(..) )")
public void demandRefund(a) {
System.out.println("Demanding a refund");
}
Copy the code
Note: The @AfterThrowing annotation is used to define the exception notification method that is called after the target method throws an exception
3.6 Defining reusable pointcut expressions
If you are careful, you may notice that the Pointcut expression is the same in all five pointcuts we defined above. This is obviously not good, but we can use the @pointcut annotation to define a Pointcut expression that can be reused:
/** ** reusable pointcuts */
@Pointcut("execution(* chapter04.concert.Performance.perform(..) )")
public void perform(a) {}Copy the code
Then each of the five previously defined pointcuts can reference this pointcut expression:
Before the performance, the audience took their seats
@Before("perform()")
public void takeSeats(a) {
System.out.println("Taking seats");
}
/** * Before the performance, put your mobile phone on silent */
@Before("perform()")
public void silenceCellPhones(a) {
System.out.println("Silencing cell phones");
}
/** * The show ends, whether the show succeeds or fails */
@After("perform()")
public void finish(a) {
System.out.println("perform finish");
}
/** * clap */ after the performance
@AfterReturning("perform()")
public void applause(a) {
System.out.println("CLAP CLAP CLAP!!!");
}
/** * After the performance failed, the audience demanded a refund */
@AfterThrowing("perform()")
public void demandRefund(a) {
System.out.println("Demanding a refund");
}
Copy the code
3.7 Unit Tests
Create a new configuration class ConcertConfig as follows:
package chapter04.concert;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class ConcertConfig {
@Bean
public Audience audience(a) {
return newAudience(); }}Copy the code
Note: Unlike in the past, we used the @enableAspectJAutoProxy annotation, which is used to enable automatic proxy.
Create a new Main class and add the following test code to its Main () method:
package chapter04.concert;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = newAnnotationConfigApplicationContext(ConcertConfig.class); Performance performance = context.getBean(Performance.class); performance.perform(); context.close(); }}Copy the code
Run the code and the output looks like this:
Silencing cell phones
Taking seats
Play “Sleep No More”
perform finish
CLAP CLAP CLAP!!!
Modify the SleepNoMore class’s Perform () method slightly to throw an exception:
@Override
public void perform(a) {
int number = 3 / 0;
System.out.println("Play" Sleep No More.");
}
Copy the code
Run the code again and the output looks like this:
Silencing cell phones
Taking seats
perform finish
Demanding a refund
Exception in thread “main” java.lang.ArithmeticException: / by zero
This also indicates that the @After annotation executes regardless of whether the target method executes successfully, but the @AfterRETURNING annotation executes only when the target method executes successfully.
It is important to note that the Aspect class annotated with @Aspect must bea bean(regardless of how it is declared), otherwise the Aspect will not take effect, because AspectJ automatic proxies will only create proxy classes for beans annotated with @Aspect.
That is, if we remove or comment out the following code from the ConcertConfig configuration class:
@Bean
public Audience audience(a) {
return new Audience();
}
Copy the code
The result will be:
Play “Sleep No More”
3.8 Creating surround Notifications
You can create circular notifications using the @around annotation, which allows you to customize your logic before and after calling the target method.
Therefore, the 5 pointcuts defined before can now be defined in one pointcut. In order not to affect the previous pointcut, we create a pointcut, as shown below: AroundAudience
package chapter04.concert;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class AroundAudience {
/** * reusable pointcuts */
@Pointcut("execution(* chapter04.concert.Performance.perform(..) )")
public void perform(a) {}@Around("perform()")
public void watchPerform(ProceedingJoinPoint joinPoint) {
try {
System.out.println("Taking seats");
System.out.println("Silencing cell phones");
joinPoint.proceed();
System.out.println("CLAP CLAP CLAP!!!");
} catch (Throwable throwable) {
System.out.println("Demanding a refund");
} finally {
System.out.println("perform finish"); }}}Copy the code
Note here that the method has a parameter of type ProceedingJoinPoint, and the target method can be called within the method by calling its PROCEED () method.
Then modify the ConcertConfig class:
package chapter04.concert;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class ConcertConfig {
/*@Bean public Audience audience() { return new Audience(); } * /
@Bean
public AroundAudience aroundAudience(a) {
return newAroundAudience(); }}Copy the code
The running result is as follows:
Taking seats
Silencing cell phones
Play “Sleep No More”
CLAP CLAP CLAP!!!
perform finish
4. Source code and reference
Source code address: github.com/zwwhnly/spr… Welcome to download.
Craig Walls: Spring In Action (4th Edition)
AOP (aspect oriented programming) _ Baidu Encyclopedia