1.AOP概述
AOP: 全称是 Aspect Oriented Programming 即: 面向切面编程。简单的说:AOP帮助我们抽离重复代码,在原来代码基础上进行一定的包装增强,如在方法执行前、方法返回后、方法抛出异常后等地方进行一定的拦截处理或者叫增强处理。
Spring AOP
- AOP是一种思想,并不仅仅是Spring才有
- 它基于动态代理来实现。默认地,如果使用接口的,用JDK 提供的动态代理实现,如果没有接口,使用 CGLIB 实现。
- Spring AOP 需要依赖于 IOC 容器来管理,Spring AOP 只能作用于 Spring 容器中的 Bean,它是使用纯粹的 Java 代码实现的,只能作用于 bean 的方法。
- Spring AOP 是基于代理实现的,在容器启动的时候需要生成代理实例,在方法调用上也会增加栈的深度,使得 Spring AOP 的性能不如 AspectJ 那么好。
- Spring AOP 致力于解决的是企业级开发中最普遍的 AOP 需求(方法织入),而不是力求成为一个像 AspectJ 一样的 AOP 编程完全解决方案。
AOP开发相关术语
- JoinPoint:连接点,可以被拦截(增强)到的点
- pointCut:切入点,真正要被拦截(增强)到的点
- Advice:通知、增强。方法层面的增强。比如权限校验的方法被称为是通知。
- Introduction:引介,也是增强,不过是类层面的增强。一般研究的是方法层面。
- Target:目标,被增强的对象(例如userDao)
- Weaving:织入,将通知应用到目标的过程。比如将权限校验的代码应用到UserDao的save方法上的过程。
- Proxy:一个类被AOP织入增强后,产生一个结果代理类
- Aspect:切面,多个通知和多个切入点的组合

2.利用Spring完成AOP的开发
2.2 基于注解方式开发
2.2.1通知类型及API介绍
- @Aspect:指定一个类为切面类
- @Pointcut("execution(* com.zcc.service.Userservice.save(..))") 指定切入点表达式
- @Before("表达式或切入点") 前置通知: 目标方法之前执行
- @After("pointCut_()") 后置通知:目标方法之后执行(始终执行)
- @AfterReturning("pointCut_()") 返回后通知: 执行方法结束前执行(异常不执行)
- @AfterThrowing("pointCut_()") 异常通知: 出现异常时候执行
- @Around("pointCut_()") 环绕通知: 环绕目标方法执行
2.2.2切入点表达式
主要利用切入点表达式针对某些类中的方法进行增强。官网表达式语法说明
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
符号讲解: ?号代表0或1,可以不写“*”号代表任意类型,0或多,方法参数为..表示为可变参数
参数讲解:
- modifiers-pattern?【修饰的类型,可以不写】
- ret-type-pattern【方法返回值类型,必写】
- declaring-type-pattern?【方法声明的类型,可以不写】
- name-pattern(param-pattern)【要匹配的名称,括号里面是方法的参数】
- throws-pattern?【方法抛出的异常类型,可以不写】
官方也有给出一些例子给我们理解:

2.2.3代码实例
新建项目,在pom.xml中引入相关jar包地址<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
配置Spring的配置文件,编写Spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- =======================引入spring aop开发的约束 ========================= -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--打开组件扫描,启用注解配置-->
<context:component-scan base-package="com.zcc"/>
<!-- 开启aop注解开发 -->
<aop:aspectj-autoproxy/>
</beans>
编写UserService.java
package com.zcc.Service;
import org.springframework.stereotype.Service;
@Service
public class UserService {
public void save() {
System.out.println("保存用户...");
}
public void delete() {
System.out.println("删除用户...");
}
public void update() {
int i = 1/0;
System.out.println("更新用户...");
}
public void find() {
System.out.println("查询用户...");
}
}
编写切面类MyAspect.java
package com.zcc.AOP;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class MyAspect {
@Before("execution(* com.zcc.Service.UserService.save(..))")
public void before(){
System.out.println("【前置通知】权限校验....");
}
@After("execution(* com.zcc.Service.UserService.delete(..))")
public void after(){
System.out.println("【后置通知】日志记录....");
}
@Around("execution(* com.zcc.Service.UserService.find(..))")
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕前....");
pjp.proceed();//执行目标方法
System.out.println("环绕后....");
}
@AfterThrowing("pt()")
public void afterThrowing(){
System.out.println("afterThrowing()....");
}
@Pointcut("execution(* com.zcc.Service.UserService.update(..))")
public void pt(){
}
}
编写测试类
@org.junit.Test
public void demo4() {
//使用工厂类去读取配置文件去创建并存储对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring.xml");
//获取代理对象
UserService userService = applicationContext.getBean("userService", UserService.class);
System.out.println(userService.getClass());
userService.save();
userService.delete();
userService.update();
userService.find();
}
运行结果如下:

2.3基于XML方式开发
去掉上述所有的注解,重新编写Spring的配置文件<?xml version="1.0" encoding="UTF-8"?>
<!-- =======================引入spring aop开发的约束 ========================= -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService2" class="com.zcc.Service.UserService2"></bean>
<bean id="myAspect2" class="com.zcc.AOP.MyAspect2"></bean>
<!-- 通过aop的配置来对目标类产生代理 -->
<aop:config>
<!--配置切入点,定义对谁进行拦截增强-->
<aop:pointcut id="point1" expression="execution(* com.zcc.Service.UserService.save(..))"/>
<aop:pointcut id="point2" expression="execution(* com.zcc.Service.UserService.delete(..))"/>
<!--配置切面类-->
<aop:aspect ref="myAspect2">
<!--配置用切面类的哪个方法进行增强-->
<aop:before method="before" pointcut-ref="point1"/>
<aop:after method="after" pointcut-ref="point2"/>
</aop:aspect>
</aop:config>
</beans>