AOP入门
1.AOP简介
AOP是面向切面编程的意思,全称为Aspect Oriented Programing。他是一种基于OOP之上的一种编程范式,他弥补了OOP的不足,能更好的组织程序结构!
AOP可以把业务的功能步骤做成插拔式的组件(这种开发方式也叫“横向开发”),从而可以用这些组件定制新的功能。因此AOP可以提高业务的复用性,提高开发效率!
2.AOP与OOP的对比
OOP是面向对象编程的意思,以OOP思想指导的程序开发过程就是在建模(类)、创建对象、指挥对象做事情!所以说OOP的开发实际上是根据业务创建模型,基于模型展开业务开发。为了降低程序开发的复杂度,程序开发者们又对OOP下的WEB程序进行了分层设计。
经典的分层设计为:控制层、业务层、持久层。如下图所示:
现在的WEB程序设计基本上都会遵循上面的分层设计原则,每个WEB项目在每个层次的设计过程中或多或少都会有相同的操作步骤或者业务逻辑!也就是说某些项目之间或多或少都有些重复功能的业务代码!这就是项目之间的共性!如果想提高开发效率,就可以将共性功能抽取出来,做成单独的一个组件,各个项目如果要用到这些功能的时候,之间拼接上去就行了!---------这就是AOP要做的事情!
AOP范式编程研究的不是层与层之间的关系,也不是每层内部如何开发,AOP主要关注同一层面的各个不同功能模块之间的共性功能。
3.AOP 的底层实现
实际上,AOP 的底层是通过 Spring 提供的的动态代理技术实现的。在运行期间,Spring通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用目标对象的方法,从而完成功能的增强。
AOP 的动态代理技术
- JDK 代理 : 基于接口的动态代理技术
- cglib 代理:基于父类的动态代理技术
4.AOP基本概念
- 连接点(Joinpoint)(类中所有方法)
- 切入点(Pointcut)(确实共性功能代码的方法)
- 通知(Advice)(被抽取的共性功能的代码逻辑,通知有位置区分,也就是从切入点方法中被抽取代码的前面还是后面抽象出来的代码,叫通知类型。前置通知、后置通知)
- 引入(Introduction)(了解,通知只能抽取逻辑代码,变量是拿不出来的,把变量引入到切入点方法中去,就要用引入)
- 目标对象(Target Object):有切入点方法的对象
- AOP代理(AOP Proxy):Spring代理目标对象就叫做AOP代理
- 织入(Weaving):代理对象把通知织入到目标对象的切入点方法中,是一个动作
- 切面(Aspect):通知和切入点之间的关系
连接点(Joinpoint)
程序运行过程中,JVM负责程序运行。执行到某个方法时,JVM能识别当前执行的是哪个方法。这些定义在类中的方法,每个具有独立的功能,在AOP中,将这些具有特定功能的方法称为连接点。
连接点指类中的方法
切入点(Pointcut)
类中的方法具有很多,某些方法具有一些共同的流程,例如数据库连接的获取与关闭,事务的开启与提交,等等。将这些公共的特性抽取出来,抽取完毕后,原始方法中就缺少了这些被抽取的代码。在实际运行时,缺少这些代码是无法完成原始的功能的。这些被抽取了公共功能的方法称为切入点。
切入点指被抽取了共性功能的方法
切入点一定是连接点,连接点不一定是切入点
通知(Advice)
切入点对应的方法的共性功能被抽取后,组成独立代码逻辑,被封装在某个类的某个方法中,在被抽取了共性功能的方法被执行时,这些代码逻辑还要加入原始方法的执行,这些被抽取出来组成独立代码逻辑的共性功能称为通知。
共性功能被抽取后,可能来自于切入点对应的方法中的任何位置,因此通知不仅描述共性的代码逻辑,还是描述被抽取时从何处抽取。例如切入点代码逻辑的前面、中间还是后面,被抽取的代码在切入点中的具体位置,称为通知类别。
引入(Introduction)(了解)
通知仅表示切入点被抽取的代码逻辑,对于切入点所在的类,如果存在有共性的成员变量或者成员方法,通知将无法进行描述。AOP提供引入机制,将共性功能的成员进行加入。
引入机制可以为类添加额外的成员变量或者成员方法
引入机制是在编译期或类加载期完成的
目标对象(Target Object)
切入点对应的共性功能被抽取后创建独立的通知完成共性功能,在程序运行时,动态的为类对象执行切入点方法时动态加入被抽取的共性功能,此时需要使用代理的模式完成。此时被代理创建的对象,称为目标对象。
目标对象指包含切入点的类对象
AOP代理(AOP Proxy)
切入点所在的类对象执行切入点方法时,需要将原始的共性功能(通知)加入,此时通过代理的形式创建类对象,并完成共性功能(通知)的加入,上述过程称为AOP代理。
AOP代理的意义是将被抽取共性功能的类对象创建出,同时将共性功能(通知)加入,完成原始的完整操作的执行过程。
切面(Aspect)(在配置文件中配置切面)
切面是一个设计概念,指切入点与通知的匹配模式,换句话说指被抽取了共性功能的方法(切入点)与被抽取了共性功能(通知)对应的绑定关系。
程序设计时,可以设置多个切面,用来描述切入点与通知之间的关系。
织入(Weaving)
通过AOP代理,完成了切入点与通知的融合,并组成了完整的代码逻辑,将通知加入到切入点对应位置的动作称为织入。
织入是一个动态过程,不对应任何代码,可以理解为动态的运行过程。
织入可以在三个阶段进行,编译时,类加载时,运行时。Spring采用的是运行时织入。
5.Spring的AOP实例
导入相关依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
创建目标对象
public class TargetObj {
public void method1(){
//System.out.println(1); 共性的功能,把抽取出来的代码做成通知,放在通知类中
System.out.println(2);
System.out.println(3);
}
public void method2(){
System.out.println(2);
System.out.println(3);
}
}
创建通知类
//通知类:抽取目标对象中共性的代码
public class MyAdvice {
public void one(){
System.out.println(1);
}
}
开启AOP空间的支持(XML命名空间)
<?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: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">
/beans>
配置AOP的切面
<!--对aop进行配置-->
<aop:config>
<!--配置切面-->
<!--配通知和切入点间的关系-->
<!--要把通知和切入点所在的类配置成Spring的bean-->
<aop:aspect ref="advice">
<!--配置切面,把通知类中的方法和目标对象中的方法关联-->
<aop:before method="one" pointcut="execution(public void com.lrx.demo.TargetObj.method1())"/>
</aop:aspect>
</aop:config>
<bean id="target" class="com.lrx.demo.TargetObj"></bean>
<bean id="advice" class="com.lrx.demo.MyAdvice"></bean>
测试
public class AopTest {
@Test
public void test1(){
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
TargetObj target = (TargetObj) app.getBean("target");
target.method1();
System.out.println("---------------");
target.method2();
}
}
6.切入点表达式及通配符
作用:用来匹配切入地方法
格式:**execution(**切入点表达式)
execution([方法的访问控制修饰符] 方法的返回值 包名.类名/接口名.方法名(参数))
注意:方法的访问控制修饰符可以省略,写方法名的时候要把包名和类名全部带上或者正确利用通配符来省略
通配符:*,…(表示任意多个包、参数)
1、 可以匹配返回值类型
2、 可以匹配包名
3、 可以匹配类名
4、 可以匹配方法名
5、 可以匹配参数
7.AOP通知类型
通知类型就是共性代码是在目标对象方法的代码的前面还是后面执行的类型就是通知类型。
类型:位置的意思
AOP的通知类型共5种
1、 before:前置通知(应用:各种校验)
在方法执行前执行
该方法中出现了异常,不会影响前置通知的执行
2、 after:后通知(应用:清理现场)
方法执行完毕后执行,无论方法中是否出现异常都会执行
3、afterReturning:返回后通知(应用:常规数据处理)
方法正常返回后执行,如果方法中抛出异常,无法执行
4、afterThrowing:抛出异常后通知(应用:包装异常信息)
方法抛出异常后执行,如果方法没有抛出异常,无法执行
5、around:环绕通知(应用:十分强大,可以做任何事情)
方法执行前后分别执行,如果方法中有异常,末尾的通知就不执行了