AOP产生背景
使用面向对象编程 ( OOP )有一些弊端,当需要为多个不具有继承关系的对象引人同一个公共行为时,例如日志、安全检测等,我们只有在每个对象里引用公共行为,这样程序中就产生了大量的重复代码,程序就不便于维护了。
所以就有了一个对面向对象编程的补充,即面向方面编程 ( AOP ), AOP 所关注的方向是横向的,区别于 OOP 的纵向。
什么是AOP
什么是面向方面编程,3个过程:
-
找到横切点:首要目标确定在程序的哪个位置进行横切逻辑
-
横切逻辑(业务代码):横切逻辑代码,这个就是横切业务代码,与aop无关
-
织入:将横切逻辑织入到横切点
开发者主要关心的是横切逻辑的编写,只需要很少的代码编写确定横切点有哪些,而不需要去为每个横切点添加横切逻辑,不然就是面向对象编程了。
既然是横向的编程,那么在我们的程序中,哪些可以作为横线切入点呢?
看下示例代码:
public class Test {
public static void main(String[] args) {
//@1
B b = new B();
//@2
b.method();
//@3
B.say();
}
static class B {
//字段
//@4
private String name;
//构造方法
public B() {
//@1.1
}
//对象方法
public void method(){
//@2.2
}
//静态方法
static void say(){
//@3.3
}
}
}
所以我们可以将横切点主要分为两大类:字段、方法。方法又分为很多种,
横切点有很多地方,从代码上看得见的,有如下几个地方:
-
使用构造函数创建对象
-
构造函数执行
-
对象方法调用
-
对象方法执行
-
静态方法调用
-
静态方法执行
-
反射读写对象字段
AOP中的核心概念【理解】
引入:加入我有一个类中有四个方法,update,save,save,select
public class StudentDaoImpl implements StudentDao {
@Override
public void save() {
System.out.println("Student dao save ...");
}
@Override
public void update() {
System.out.println("Student dao update ...");
}
@Override
public void save() {
System.out.println("Student dao delete ...");
}
@Override
public void select() {
System.out.println("Student dao select ...");
}
现在有一个需求:对save方法进行增强,循环输出1000次语句到控制台,并计算运行时间,那么我们可能这样
@Override
public void save() {
//开始时间
Long start =System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
System.out.println("Student dao save ...");
}
//结束时间
Long end =System.currentTimeMillis();
System.out.println("耗时: "+ (end-start)+" ms");
}
现在问题来了,假设我需要将类中的save,select,update这三个方法都统计一下耗时,我该怎么做?
可以对每一个需要统计的方法都按照save方法一样进行修改代码,那么这样写麻不麻烦大家自己想一下。
答案是肯定的,所以我们就要使用新的方式去解决这个问题,这就是AOP(面向切面编程)
-
连接点(JoinPoint):正在执行的方法,例如:update()、delete()、select()等都是连接点。
-
切入点(Pointcut):进行功能增强了的方法,例如:update()、delete()方法,select()方法没有被增强所以不是切入点,但是是连接点。
-
一个具体方法:com.itheima.dao包下的BookDao接口中的无形参无返回值的save方法
-
匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法
-
在SpringAOP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
-
-
通知(Advice):在切入点前后执行的操作,也就是增强的共性功能
-
在SpringAOP中,功能最终以方法的形式呈现
-
-
通知类:通知方法所在的类叫做通知类
-
切面(Aspect):描述通知与切入点的对应关系,也就是哪些通知方法对应哪些切入点方法。
AOP工作流程
问题导入
什么是目标对象?什么是代理对象?
AOP工作流程
-
Spring容器启动
-
读取所有切面配置中的切入点
-
初始化bean,判定bean对应的类中的方法是否匹配到任意切入点
-
匹配失败,创建原始对象
-
匹配成功,创建原始对象(目标对象)的代理对象
-
-
获取bean执行方法
-
获取的bean是原始对象时,调用方法并执行,完成操作
-
获取的bean是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作
-
AOP核心概念
-
目标对象(Target):被代理的对象,也叫原始对象(StudentDaoImpl),该对象中的方法没有任何功能增强。
-
代理对象(Proxy):代理后生成的对象,由Spring帮我们创建代理对象。
在测试类中验证代理对象
@Test
public void testAop() {
System.out.println("也对对象类型: "+studentDao.getClass());
studentDao.update();
}