什么是AOP?面向切面编程(Aspect Oriented Programming)。
什么是OOP? 面向对象编程(Object Oriented Programming)。
AOP和OOP一样都是一个编程思想,OOP主要功能封装、继承、多态,AOP它是将系统分解为不同的关注点(不同的切面)。
OOP,我们会根据业务将应用划分为多个不同的业务模块,每个模块的核心功能只为某个核心业务提供服务,如学生宿舍管理系统,学生管理、班级管理、房间管理,分别学生、班级、房间服务的。
除此之外,还会有一些非业务的通用功能,如日志、权限、事务管理等。它们和业务无关,但是几乎所有的模块都会用到它。因此这些通用功能会散布在不同的业务模块中。此时会有很多重复性的代码,不利模块的复用。
为了解决这个问题,AOP(面向切面编程)就出来了,它是把非业务的通用功能抽取出来单独维护,并通过声明的方式(定义切入点)去指定这些功能以何种方式(通知类型)作用在哪里(方法连接点--目标方法),而不是直接在模块的代码中去直接添加。
AOP和OOP的目的是一致的,都是为了减少程序中的重复性代码,让开发者把精力集中于业务逻辑,只是它们的实现方式不同。OOP(婉约派),使用继承和组成方式,为通用功能提高代码复用。AOP(豪放派),通过切入点规定,在某包某类某方法中,去添加同样操作。
AOP不是用来替换OOP的,而是OOP的延伸,用来解决OOP中遇到的问题。
AOP术语
切面:由通知和切入点组成。
连接点:应用程序执行过程中插入切面的地点,一般多为方法。
通知:切面中非核心业务通用功能的具体实现代码。
切入点:定义通知应该在应用程序的什么位置(连接点)。
目标对象:被通知的对象。
代理:将通知应用到目标对象后创建的对象。
织入:将切面应用到目标对象从而创建一个新的代理对象的过程。
AOP的关键就在于能够创建切入点,定义切面中的通知在那些连接点织入。
基于注解的AOP应用
1.导入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
2.在Spring中心配置类中,加入注解@EnableAspectJAutoProxy,开启AOP支持。
3.创建切面--就是一个带有@Aspect注解的类。
@Aspect // 标识此类为切面
@Component
public class FirstAspect {
// 书写通知和切入点
}
3.1 定义切入点
/*
使用 @Pointcut 定义一个切入点
注意:1.切入点定义需要搭配方法
2.返回值类型必须是void,访问修饰符是private
在定义切入点时,需要指明切入点是连接哪一个连接点,此时需要使用切入点(execution)表达式去说明
execution语法格式:
execution(返回值类型 类的全限定名.方法名称(参数列表))
返回值类型: * -- 表示可以为任何返回值,如果返回值为对象需要写全限定类名
类的全限定名:包名 + 类名 * -- 可以为任何类
特殊含义符号:* --表示匹配任意数量的字符
.. 匹配任何数量的字符重复,
如果在全限定类名处使用..,则表示匹配任何数量的子包
如果在方法参数中使用..,则表示匹配任意数量参数
*/
@Pointcut("execution(* com.project..UserService.t*(..))")
private void myPointcut(){}
3.2 定义通知
/*
通知有5种类型:
@Before 前置通知,在方法执行前执行
@After 后置通知,在方法执行后执行,方法无论有没有异常都会执行
@AfterReturning 返回通知,在方法正常结束之后执行
@AfterThrowing 异常通知,在方法抛出异常后执行
@Around 环绕通知,围绕着方法执行
*/
@Pointcut("execution(* com.project..ManService.*(..))")
private void pointcut(){}
@Before("pointcut()")
public void before(){
System.out.println("这是前置通知");
}
@After("pointcut()")
public void after(){
System.out.println("这是后置通知");
}
@AfterReturning("pointcut()")
public void afterReturning(){
System.out.println("这是方法正常结束之后的--返回通知");
}
@AfterThrowing("pointcut()")
public void afterThrowing(){
System.out.println("方法出现异常--异常通知");
}
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) {
/* ProceedingJoinPoint 的proceed方法去执行目标方法
ProceedingJoinPoint 的getSignature方法获取目标方法的信息
ProceedingJoinPoint 的getTarget方法获取目标对象*/
Object obj = null;
try {
System.out.println("环绕前通知" + joinPoint.getSignature());
Object target = joinPoint.getTarget();
System.out.println(target.getClass().getSimpleName());
obj = joinPoint.proceed();// 执行目标方法
System.out.println("环绕后通知");
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return obj;
}