1. Introduction to Spring's AOP
1.1 What is AOP?
AOP is the abbreviation of Aspect Oriented Programming, which means aspect-oriented programming,
It is a technology that realizes the unified maintenance of program functions through pre-compilation and runtime dynamic agents.
AOP is the continuation of OOP (Ojebct Oriented Programming), a hot spot in software development, an important part of the Spring framework, and a derivative paradigm of functional programming. Using AOP can isolate each part of the business logic, thereby reducing the coupling between each part of the business logic, improving the reusability of the program, and improving the efficiency of development.
Limitations of OOP
There are usually log control, performance statistics, security control, transaction control, exception handling and other operations in business code. Although using OOP can achieve code reuse through encapsulation or inheritance, there is still the same code scattered in each method. , The use of OOP to process logs, etc. enhances the workload of developers, and increases the difficulty of upgrade and maintenance
These horizontal lines seem to cut the OOP tree structure, like a big cake being cut into multiple layers, each layer will execute the same auxiliary logic, so we call these auxiliary logic levels or aspects.
1.2 Advantages of AOP
Role: During program execution, the method is enhanced without modifying the source code
Advantages: Reduce repetitive code, improve development efficiency, and facilitate maintenance.
1.3 The underlying implementation of AOP
In fact, the bottom layer of AOP is realized through the dynamic proxy technology provided by Spring. During operation, Spring dynamically generates proxy objects through dynamic proxy technology. When the proxy object method is executed, the enhancement function is involved, and the method of the target object is called to complete the function enhancement.
1.4 AOP proxy technology
Commonly used dynamic proxy technology
- JDK proxy: Interface-based dynamic proxy technology
- cglib proxy: dynamic proxy technology based on parent class
Commonly used dynamic proxy technology
- JDK proxy: Interface-based dynamic proxy technology
- cglib proxy: dynamic proxy technology based on parent class
1.5 JDK's dynamic proxy
- target class interface
public interface TargetInterface{
void save();
}
2. Target class
public class Target implements TargetInterface{
public void save(){
System.out.println("save running....");
}
}
- add class
public class Advice{
public void before(){
System.out.println("前置增强");
}
public void afterReturning(){
System.out.println("后置增强...");
}
}
- dynamic proxy code
public class ProxyTest{
public static void main(String [] args){
// 目标对象
final Target target = new Target();
// 增强对象
final Advice advice = new Advice();
//返回值 就是动态生成的代理对象
TargetInterface proxy = (TargetInterface)Proxy.newProxyInstance(
// 目标对象类加载器
target.getClass().getClassLoader(),
// 目标对象相同的接口字节码对象数组
target.getClass().getInterfaces(),
new InvocationHandler() {
// 调用代理对象的任何方法 实质执行的都是invoke方法
public Object invoke(Object proxy,Method method, Object[] args) throws InvocationTargetException, IllegalAccessException{
advkce.before(); // 前置增加
Object invoke = method.invoke(target,args) //执行目标方法
advice.afterReturning(); //后置增加
return invoke; // 返回值就是目标对象 -> null也行(尽量别)
}
}
);
// 调用代理对象方法
proxy.save();
// (调用接口的任意方法时,代理对象的代码都无需修改)
}
}
Output result:
前置增加
save running.....
后置增加
1.6 Dynamic proxies for cglib
1) target class
public class Target {
public void save() {
System.out.println("save running.....");
}
}
2) Enhanced class object
public class Advice {
public void before(){
System.out.println("前置增强....");
}
public void afterReturning(){
System.out.println("后置增强....");
}
}
3) Dynamic proxy code
public class ProxyTest {
public static void main(String[] args) {
// 目标对象
final Target target = new Target();
// 增加对象
final Advice advice = new Advice();
// 返回值 就是动态生成的代理对象 基于从cglib
// 1. 创建增强器
Enhancer enhancer = new Enhancer();
// 2. 设置父类(目标)
enhancer.setSuperclass(Target.class);
// 3. 设置回调
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//执行前置
advice.before();
Object invoke = method.invoke(target, args);
// 执行后置
advice.afterReturning();
return invoke;
}
});
// 4. 创建代理对象
Target proxy = (Target) enhancer.create();
proxy.save();
}
}
1.7 Related concepts of AOP
The bottom layer of Spring's AOP implementation is to encapsulate the code of the dynamic proxy above. After encapsulation, we only need to write the code for the part that needs attention, and enhance the method of completing the specified target through configuration.
AOP commonly used related terms are as follows:
- Target : The target object of the proxy
- Proxy (proxy) : After a class is enhanced by AOP weaving, it will produce a result proxy class
- Joinpoint (connection point) : The so-called connection point refers to those points that are intercepted. In spring, these points refer to methods, because spring only supports connection points of type method
- Pointcut : The so-called pointcut refers to the definition of those JoinPoints that we want to intercept
- Advice (notification/increase) : The so-called notification is that what you need to do after intercepting the Joinpoint is to notify
- Aspect (aspect) : is a combination of pointcut and advice (introduction)
- Weaving : refers to the process of applying enhancements to target objects to create new proxy objects. Spring uses dynamic proxy weaving, while AspectJ uses compile-time weaving and class loading-time weaving
Spring AOP terminology:
Difference between join point and tangent point
- Join point: A join point is a point at which an aspect can be inserted during application execution. These points can be when a method is called or even when a field is modified.
- Pointcut: Pointcut refers to the specific position of the place where the Adivce is to be woven
Connection point : A connection point is a concept of 虚拟
, which can be understood as all the times that satisfy the pointcut condition.
A specific example: For example, driving through a highway, this highway has many junctions (connection points), but we will not go out every exit, the commander chooses the exit (cut point) we need to drive out.
It can be easily understood that each exit is 连接点
but the exit we use is 切点
, each application has multiple locations suitable for weaving notifications, these are connection points , but only the specific location we choose is the tangent point
Small summary: all methods require join points, pointcuts are our implementation of join points, and pointcuts determine which join points need to be processed.
Reference: https://blog.csdn.net/weixin_42649617/article/details/109997718
AOP development clear development and summary
what needs to be written
- Write the target side of the target class)
- Write a facet class (with enhanced methods)
- In the configuration file, configure the weaving relationship, and those
通知
and连接点
collections
Summarize
key concept of aop
Pointcut: the enhanced method
Advice (notification/enhancement): encapsulates methods for enhancing business logic
Aspect: pointcut + notification
Weaving: The process of combining pointcuts with advice
developer steps
Who is the pointcut (pointcut expression)
Who is the notification (enhanced method of the aspect class)
Weave pointcuts and advice into configuration
XML-based AOP Development
2.1 Quick Start
- Coordinates for maven AOP
- target interface target class (with pointcut inside)
- Sliced
- Configure weaving etc in applicationContext.xml
- test
1. Guide package
<dependencies>
<!-- 导入spirng的context坐标,context依赖aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!-- aop小框架 aspectj的织入 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- 这是一个spring自带的测试等等我会演示 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
</dependencies>
2. Target interface target class (with pointcut inside)
package com.xxx.aop; // 目标接口
public interface TargetInterface {
public void save();
}
package com.xxx.aop; // 目标类
public class Target implements TargetInterface {
public void save() {
// int i = 1/0;
System.out.println("save running.....");
}
}
3. Aspect class (with internal enhancement methods)
package com.xxx.aop;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAspect {
public void before(){
System.out.println("前置增强......");
}
}
4.xml for configuration
- aop namespace and constraint space
xml code
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
">
<!-- 目标对象 -->
<bean id="target" class="com.xxx.aop.Target"></bean>
<!-- 切面对象 -->
<bean id="myAspect" class="com.xxx.aop.MyAspect"></bean>
<!-- 配置织入: 告诉spring框架 那些方法(切点)需要进行那些增强(前置,后置..)-->
<aop:config>
<!-- 声明切面 -->
<aop:aspect ref="myAspect">
<!-- 配置Target的save方法执行时要进行myAspect的before方法前置增强 -->
<!--切面: 切点+通知(增加) pointcut切点 -->
<aop:before method="before" pointcut="execution(public void com.xxx.aop.Target.())"/>
</aop:aspect>
</aop:config>
</beans>
5. Test
@RunWith(SpringJUnit4ClassRunner.class) // spring测试类
@ContextConfiguration("classpath:applicationContext.xml") // 指定测试的文件
public class AopTest {
@Autowired // 把要测试的对象 注入进来
private TargetInterface target;
@Test
public void test1() {
target.save();
}
}
Output result:
Pre-enhancement...
save running.....
Detailed explanation of xml configuration AOP
1) How to write a pointcut expression
Expression syntax
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
- modifier can be omitted
- Return value type, package name, class name, method name can use asterisk * to represent any
- A dot between the package name and the class name
.
represents the class under the current package, and two dots..
represent the classes under the current package and its subpackages - The parameter list can use two dots
..
to indicate any number, any type of parameter list
# 全
execution(public void com.xxx.aop.Target.method())
# 任意方法任意参数
execution(void com.xxx.aop.Target.*(..))
# 任意返回值com.xxx.aop包下任意类任意方法任意参数
execution(* com.xxx.aop.*.*(..))
# 任意返回值com.xxx.aop下以其子包下任意类任意参数
execution(* com.xxx.aop..*.*(..))
# 你故意找茬是吧
execution(* *..*.*(..))
小总结:
修饰符可以不写
第一个 * = 返回值
第二个 * = 包
第三个 * = 类
第四个 * = 方法
括号外.. = 自己包括子包下所有类的xxx
括号内的 .. = 任意参数
2) Type of notification
Configuration syntax for notifications:
<aop:通知类型 method="切面类中方法名" pointcut="切点表达式"></aop:通知类型>
name | Label | illustrate |
---|---|---|
advance notice | <aop:before> | Used to configure pre-notification. Specifies that the enhanced method executes before the pointcut method |
post notification | <aop:after-returning> | Used to configure post notification. Specifies that the enhanced method is executed after the pointcut method |
Surround Notification | <aop:around> | for configuring surround notifications. Specifies that the enhanced method is executed both before and after the pointcut method |
exception throw notification | <aop:throwing> | Used to configure exception throw notifications. Specifies that the enhanced method executes when an exception occurs |
final notice | <aop:after> | Used to configure final notification. Will be executed regardless of whether there is an exception in the enhanced mode execution |
3) Extraction of pointcut expressions
When multiple enhanced pointcut expressions are the same, the pointcut expression can be extracted, and the pointcut-ref
attribute can be used in the enhancement to replace the pointcut
attribute to refer to the extracted pointcut expression Mode.
<aop:config>
<!--引用myAspect的Bean为切面对象-->
<aop:aspect ref="myAspect">
<!--抽取切点表达式-->
<aop:pointcut id="myPointcut" expression="execution(* com.itheima.aop.*.*(..))"></aop:pointcut>
<aop:around method="around" pointcut-ref="myPointcut"/>
<aop:after method="after" pointcut-ref="myPointcut"/>
</aop:aspect>
</aop:config>
The notification method exists in the aspect class and enhances the pointcut according to the pointcut expression.
3. Annotation-based AOP development
3.1 Quick Start
step:
1. Create the target interface and target class (enable annotation scanning)
2. Create an aspect class (open annotation scanning configuration weaving relationship)
3. xml enables component scanning and automatic proxy of AOP
4. Test
1. Create the target interface and target class (with pointcuts inside)
public interface TargetInterface {
public void save();
}
@Component
public class Target implements TargetInterface {
public void save() {
System.out.println("save running.....");
}
}
2. Create a facet class (with internal enhancement methods)
@Component("myAspect")
@Aspect //标签当前MyAspect是一个切面类
public class MyAspect {
// 配置前置增强
// @Before(value = "execution( * com.xxx.anno.*.*(..))")
public void before(){
System.out.println("前置增强......");
}
}
5. Enable component scanning and automatic proxy of AOP in the configuration file
<!--组件扫描-->
<context:component-scan base-package="com.itheima.anno"/>
<!--aop自动代理-->
<aop:aspectj-autoproxy/>
6. Test
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-anno.xml")
public class AnnoTest {
@Autowired
private TargetInterface target;
@Test
public void test1() {
target.save();
}
}
output:
Pre-enhancement...
save running.....
3.2 Annotation configuration AOP detailed explanation
1) Type of annotation notification
Configuration syntax for notifications: @通知注解("切点表达式")
name | annotation | illustrate |
---|---|---|
advance notice | @Before | Used to configure pre-notification. Specifies that the enhanced method executes before the pointcut method |
post notification | @AfterReturning | Used to configure post notification. Specifies that the enhanced method is executed after the pointcut method |
Surround Notification | @Around | Used to configure wraparound notifications. Specifies that the enhanced method is executed both before and after the pointcut method |
exception throw notification | @AfterThrowing | Used to configure exception throw notification. Specifies that the enhanced method executes when an exception occurs |
final notice | @After | Used to configure final notification. Will be executed regardless of whether there is an exception in the enhanced mode execution |
2) Extraction of pointcut expressions
Like configuring aop through xml, we can extract pointcut expressions. The extraction method is to define a method in the aspect , use the @Pointcut
annotation to define the pointcut expression on the method, and then refer to it in the enhanced annotation. details as follows:
@Component("myAspect")
@Aspect //标注当前MyAspect是一个切面类
public class MyAspect {
//Proceeding JoinPoint: 正在执行的连接点===切点
//@Around("execution(* com.xxx.anno.*.*(..))")
@Around("pointcut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕前增强....");
Object proceed = pjp.proceed();//切点方法
System.out.println("环绕后增强....");
return proceed;
}
public void afterThrowing() {
System.out.println("异常抛出增强..........");
}
//@After("execution(* com.xxx.anno.*.*(..))")
@After("MyAspect.pointcut()")
public void after() {
System.out.println("最终增强..........");
}
//定义切点表达式
@Pointcut("execution(* com.xxx.anno.*.*(..))")
public void pointcut() {
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。