Spring(3)-AOP aspect-oriented programming

Table of contents

1. Problems caused by adding functions

2. The concept of AOP

2.1 What is AOP

2.2 AOP function

2.3 Terminology in AOP

3. When to use AOP

4. Implementation of AOP technical ideas

5. Implement AOP using the AspectJ framework

5.1 Notice

5.2 Pointcut position

5.3 @before pre-notification

Variations of pointcut expressions

Notification method parameter JoinPoint

5.4 @AfterReturning post notification

5.5 @Around surround notification

5.6 @AfterThrowing exception notification

5.7 @After Final Notice

6. AOP summary


1. Problems caused by adding functions

The question arises: If you want to add new functions before and after a complex business method that has been implemented, how do you do it using the traditional method?

Add new functionality to the business methods in the source code,

1) The source code may be changed a lot

2) Lots of heavy code

3) The code is difficult to maintain

2. The concept of AOP

2.1 What is AOP

AOP (Aspect Orient Programming): Aspect-oriented programming

Aspect: Represents aspects. The functions added to business methods are called aspects. Aspects are generally non-business functions, and aspect functions are generally reusable. For example: log function, transaction function, permission check, parameter check, statistical information, etc.

Orient: facing, looking at

Programming: Programming

How to understand aspect-oriented programming? Design and develop your application with aspects as the core

1) When designing a project, find out the functions of the aspects.

2) Arrange the execution time and execution location of aspects.

2.2 AOP function

1) Reuse aspect functions

2) Let developers focus on business logic and improve development efficiency

3) Realize decoupling of business functions and other non-business functions

4) Add functions to existing business methods without modifying the original code

2.3 Terminology in AOP

1) Aspect : Aspect, the function added to the business method.

2) JoinPoint : Connection point, business method for connecting aspects. When this business method is executed, the aspect functions will be executed at the same time.

3) Pointcut : A pointcut is a collection of one or more connection points. It means that when these methods are executed, they can increase the functionality of aspects. Indicates the location where the aspect is executed.

4) target : Target object, to which object the aspect function is added, this object is the target object.

5)Advice : Advice, indicating the execution time of the aspect, whether the aspect is executed before the target method or after the target method.

Three important elements in AOP: Aspect, Pointcut, and Advice. The understanding of this concept is: Aspect is executed at the time of Advice and at the position of Pointcut.

AOP is a dynamic idea. During the running of the program, a proxy (ServiceProxy) is created, and the aspect function is added when using the proxy execution method. This proxy object is stored in memory.

3. When to use AOP

You need to add the same functionality to certain methods. The source code cannot be modified. Add non-business functionality to business methods. All can use AOP.

4. Implementation of AOP technical ideas

Use frameworks to implement AOP. There are many frameworks for implementing AOP, two of the more famous ones:

1) Spring: The Spring framework implements some functions of AOP. The operation of Spring framework to implement AOP is relatively cumbersome and cumbersome.

2) Aspectj: an independent framework specifically designed to implement AOP. Belongs to Eclipse

5. Implement AOP using the AspectJ framework

The AspectJ framework can implement AOP in two ways: annotations and xml configuration files.

5.1 Notice

Aspectj represents the execution time of the aspect, using advice. This notification can be expressed using the annotation

5 annotations represent the five execution times of the aspect. These annotations are called notification annotations.

@Before: Pre-notification

@AfterReturning: post notification

@Around : surround notification

@AfterThrowing: exception notification

@After : final notification

5.2 Pointcut position

Pointcut is used to represent the location of aspect execution, using the pointcut expression in Aspectj.

Pointcut expression syntax: execution (access permission modifier method return value method declaration (parameter) exception type)

5.3 @before pre-notification

Use the annotations of the aspectj framework to implement pre-notification:

①Business logic

package com.feiyang.service;



public interface SomeService {

void doSome(String name,Integer age);

}
package com.feiyang.service.impl;

import com.feiyang.service.SomeService;

/**

* @author:飞扬

* @公众hao:程序员飞扬

* @description:

*/

public class SomeServiceImpl implements SomeService {



@Override

public void doSome(String name, Integer age) {

System.out.println("业务方法doSome(),执行了");

}

}

②Define an aspect class:

package com.feiyang.handler;



import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;



import java.util.Date;



/**

* @author:飞扬

* @公众hao:程序员飞扬

* @description:

*/



@Aspect

public class MyAspectj {



@Before(value = "execution(public void com.feiyang.service.impl.SomeServiceImpl.doSome(String, Integer))")

public void myBefore(){

System.out.println("前置通知执行了" + new Date());

}

}

③Modify configuration file

​
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:aop="http://www.springframework.org/schema/aop"

xsi:schemaLocation="Index of /schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd Index of /schema/context https://www.springframework.org/schema/context/spring-context.xsd Index of /schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

<bean id="someService" class="com.feiyang.service.impl.SomeServiceImpl"></bean>

<bean id="myAspect" class="com.feiyang.handler.MyAspectj"></bean>

<!-- 声明自动代理生成器:目的是创建目标对象的代理 -->

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

​

④Test category:

package com.feiyang;



import com.feiyang.service.SomeService;

import org.junit.Test;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;



/**

* @author:飞扬

* @公众hao:程序员飞扬

* @description:

*/

public class Mytest01 {



@Test

public void test01(){

String config = "applicationContext.xml";

ApplicationContext ctx = new ClassPathXmlApplicationContext(config);

SomeService someService = (SomeService) ctx.getBean("someService");

System.out.println(someService.getClass().getName());

someService.doSome("张三",18);

}

}

Results of the:

com.sun.proxy.$Proxy8

Pre-notification implementedTue Oct 04 11:18:25 GMT+08:00 2022

Business method doSome(), executed

You can see that the runtime type of someService is proxy object $Proxy8.

Only when the proxy object calls methods can the aspect functions be enhanced.

Variations of pointcut expressions

package com.feiyang.handler;



import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;



import java.util.Date;



/**

* @author:飞扬

* @公众hao:程序员飞扬

* @description:

*/



@Aspect

public class MyAspectj {



//匹配指定方法

/*@Before(value = "execution(public void com.feiyang.service.impl.SomeServiceImpl.doSome(String, Integer))")

public void myBefore(){

System.out.println("前置通知执行了" + new Date());

}*/



//匹配任意访问修饰符的指定方法

/*@Before(value = "execution(void com.feiyang.service.impl.SomeServiceImpl.doSome(String, Integer))")

public void myBefore(){

System.out.println("前置通知执行了" + new Date());

}*/



//匹配任意包下的,指定参数类型的doSome方法

/*@Before(value = "execution(* *..doSome(String, Integer))")

public void myBefore(){

System.out.println("前置通知执行了" + new Date());

}*/



//匹配任意包下,任意参数类型的doSome方法

/*@Before(value = "execution(* *..doSome(..))")

public void myBefore(){

System.out.println("前置通知执行了" + new Date());

}*/



//匹配任意包下,do开头的方法

/*@Before(value = "execution(* *..do*(..))")

public void myBefore(){

System.out.println("前置通知执行了" + new Date());

}*/



//匹配任意包下任意方法

@Before(value = "execution(* *..*(..))")

public void myBefore(){

System.out.println("前置通知执行了" + new Date());

}

}

Notification method parameter JoinPoint

package com.feiyang.handler;



import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;



import java.util.Date;



/**

* @author:飞扬

* @公众hao:程序员飞扬

* @description:

*/



@Aspect

public class MyAspectj {



@Before(value = "execution(* *..*(..))")

public void myBefore(JoinPoint jp){

Object[] args = jp.getArgs();//数组中存放的是 方法的所有参数

for (Object arg : args) {

System.out.println("前置通知,获取方法的参数: " + arg);

}



String methodName = jp.getSignature().getName();

if("doSome".equals(methodName)){

System.out.println("doSome输出日志,在目标方法前先执行=" + new Date());

}else if("doOther".equals(methodName)){

System.out.println("doOther参数检查,在目标方法前先执行=" + new Date());

}else{

System.out.println("没有匹配到通知方法");

}

}

}

package com.feiyang;



import com.feiyang.service.SomeService;

import org.junit.Test;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;



/**

* @author:飞扬

* @公众hao:程序员飞扬

* @description:

*/

public class Mytest01 {



@Test

public void test01(){

String config = "applicationContext.xml";

ApplicationContext ctx = new ClassPathXmlApplicationContext(config);

SomeService someService = (SomeService) ctx.getBean("someService");

someService.doSome("张三",18);

//someService.doOther("张三",18);

}

}

Results of the:

Pre-notification, get the parameters of the method: Zhang San

Pre-notification, get the parameters of the method: 18

doSome output log, executed before the target method =Tue Oct 04 13:25:54 GMT+08:00 2022

Business method doSome(), executed

5.4 @AfterReturning post notification

@AfterReturning post notification

Attribute: value pointcut expression

returning custom variable, representing the return value of the target method

The name of the custom variable must be the same as the formal parameter name of the notification method

Position: above the method

Features:

1. Executed after the target method.

2. Able to obtain the execution results of the target method

3. Will not affect the execution of the target method

Method parameters:

Object res: Represents the return value of the target method. Use res to receive the call result of doAfter().

Object res = doAfter()。

The execution order of post-notifications:

Object res = SomeServiceImpl.doAfter();

myAfter(res);

demo:

package com.feiyang.service;


public interface SomeService {

String doAfter();

}
package com.feiyang.service.impl;



import com.feiyang.service.SomeService;


/**

* @author:飞扬

* @公众hao:程序员飞扬

* @description:

*/

public class SomeServiceImpl implements SomeService {



@Override

public String doAfter() {

System.out.println("后置通知doAfter()方法执行了");

return "res";

}

}
package com.feiyang.handler;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import java.util.Date;

/**

* @author:飞扬

* @公众hao:程序员飞扬

* @description:

*/

@Aspect
public class MyAspectj {

//后置通知

@AfterReturning(value = "execution(* *..doAfter(..))",returning = "res")

public void myAfter(Object res){

System.out.println("后置通知,在目标方法之后执行,能拿到业务执行结果:" + res);

}
}
package com.feiyang;

import com.feiyang.service.SomeService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


/**

* @author:飞扬

* @公众hao:程序员飞扬

* @description:

*/

public class Mytest01 {


@Test

public void test01(){
String config = "applicationContext.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
SomeService someService = (SomeService) ctx.getBean("someService");
someService.doAfter();
}

}

Results of the:

Post notification doAfter() method is executed

Post notification, executed after the target method, can get the business execution result: res

Note: JoinPoint jp must be the first parameter

//Post-retirement notice

@AfterReturning(value = "execution(* *..doAfter(..))",returning = "res")

public void myAfter(JoinPoint jp,Object res){

System.out.println("Post notification, executed after the target method, you can get the business execution result: " + res);

}

The following error will be reported:

//Post notification

@AfterReturning(value = "execution(* *..doAfter(..))",returning = "res")

public void myAfter(Object res,JoinPoint jp){

System.out.println("Post notification, executed after the target method, you can get the business execution result: " + res);

}

5.5 @Around notification

@Around : surround notification

Attribute: value

Position: above the method definition

Return value: Object, indicating that calling the target method hopes to get the execution result (not necessarily the return value of the target method itself)

Parameter: ProceedingJoinPoint, equivalent to Method in reflection

Function: Execute the target method, equal to Method.invoke()

Features:

1. Functions can be enhanced before and after the target method

2. Control whether the target method is executed

3. Modify the execution result of the target method

demo:

package com.feiyang.service;

public interface SomeService {
String doFirst(String name);
}

package com.feiyang.service.impl;

import com.feiyang.service.SomeService;

/**

* @author:飞扬

* @公众hao:程序员飞扬

* @description:

*/
public class SomeServiceImpl implements SomeService {

@Override
public String doFirst(String name) {
System.out.println("业务方法执行了。。。");
return "sss";
}
}
package com.feiyang.handler;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import java.util.Date;


/**

* @author:飞扬

* @公众hao:程序员飞扬

* @description:

*/


@Aspect
public class MyAspectj {


//后置通知

@AfterReturning(value = "execution(* *..doAfter(..))",returning = "res")
public void myAfter(JoinPoint jp,Object res){
System.out.println("后置通知,在目标方法之后执行,能拿到业务执行结果:" + res);
}


//环绕通知
@Around("execution(* *..doFirst(..))")
public void myAround(ProceedingJoinPoint pjp) throws Throwable {
//可以控制在业务方法执行前执行什么逻辑
System.out.println("执行了环绕通知的myAround()方法,在业务方法执行前");


//可以控制业务方法是否执行
String returnValue = (String)pjp.proceed();


//可以控制返回值
String res="";
if("aaa".equals(returnValue)){
res = returnValue;
}else{
res = "bbb";
}


//可以控制在业务方法执行后执行什么逻辑
System.out.println("执行了环绕通知的myAround()方法,在业务方法执行后: " + res);
}
}
package com.feiyang;



import com.feiyang.service.SomeService;

import org.junit.Test;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;



/**

* @author:飞扬

* @公众hao:程序员飞扬

* @description:

*/

public class Mytest01 {



//环绕通知

@Test

public void test03(){

String config = "applicationContext.xml";

ApplicationContext ctx = new ClassPathXmlApplicationContext(config);

SomeService someService = (SomeService) ctx.getBean("someService");

someService.doFirst("张三");

}



}

Results of the:

The myAround() method of the surrounding notification is executed before the business method is executed.

The business method is executed. . .

The myAround() method of the surrounding notification is executed. After the business method is executed, bbb

5.6 @AfterThrowing exception notification

//Exception notification

@AfterThrowing(value = "execution(* *..doSecond(..))", throwing = "ex")

public void myAfterThrowing(Exception ex){

System.out.println("Exception notification, an exception was thrown when executing the target method, exception reason: " + ex.getMessage());

}

@Override

public void doSecond(String name) {

int z;

z = 5/0;

System.out.println("Exception notification business method was executed.");

}

//Exception notification

@Test

public void test04(){

String config = "applicationContext.xml";

ApplicationContext ctx = new ClassPathXmlApplicationContext(config);

SomeService someService = (SomeService) ctx.getBean("someService");

someService.doSecond("lisi");

}

Results of the:

Exception notification, an exception was thrown when executing the target method, exception reason: / by zero

5.7 @AfterFinal Notice

Executed after the target method, it will always be executed and can be used to do the last work of the program, such as clearing temporary data, variables, cleaning up memory, etc.

//Final notification

@After("execution(* *..doThird(..))")

public void myAfter(){

System.out.println("Final notifications are always executed.");

}

//Final notification

@Test

public void test05(){

String config = "applicationContext.xml";

ApplicationContext ctx = new ClassPathXmlApplicationContext(config);

SomeService someService = (SomeService) ctx.getBean("someService");

someService.doThird();

}

Results of the:

The business method is executed.

Final notifications are always executed.

5.8 @Pointcut

Define and manage pointcuts, not notification annotations.

package com.feiyang.handler;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import java.util.Date;


/**

* @author:飞扬

* @公众hao:程序员飞扬

* @description:

*/

@Aspect
public class MyAspectj {

@Before(value = "mypt()")

public void method1(){

System.out.println("业务逻辑执行了");

}


@After(value = "mypt()")

public void method2(){

System.out.println("业务逻辑执行了");

}


@Pointcut("execution(* *..doThird(..))")

public void mypt(){

//无需代码

}

}

6. AOP summary

        AOP is a dynamic technical idea that aims to achieve the decoupling of business functions and non-business functions. Business functions are independent modules, and other functions are also independent business modules. Such as transaction functions, logs, etc. Make these functions, such as transactions, logs, etc., reusable.

        When the target method requires some functions, you can use AOP technology to generate proxy objects during program execution without modifying the source code, and add functions by executing the business method.

Guess you like

Origin blog.csdn.net/lu_xin5056/article/details/128975249