零、本文纲要
- 一、了解AOP
1、认识AOP
2、AOP作用
3、AOP核心概念 - 二、AOP快速入门
1、基础准备
2、AOP实现
3、总结 - 三、AOP获取通知数据
1、JoinPoint
2、ProceedingJoinPoint
3、获取通知数据的使用场景
一、了解AOP
1、认识AOP
AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构。
2、AOP作用
在不侵入原始设计的基础上,进行功能增强。
3、AOP核心概念
- ① 连接点 Join Point
程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等。在Spring AOP中可以理解为执行方法。
- ② 切入点 Pointcut
匹配连接点的式子,可以匹配一个或者多个。
- ③ 通知 Advice
在切入点处执行的操作,共性功能。
- ④ 切面 Aspect
描述通知Advice
与切入点Pointcut
的关系。
- ⑤ 通知类
定义通知的类。
二、AOP快速入门
1、基础准备
- ① 导入依赖
Ⅰ spring-context:spring核心容器bean、context相关;
org.springframework
spring-context
5.2.10.RELEASE
其中该依赖包含了AOP相关的依赖内容,如下:
Ⅱ aspectjweaver:AOP需要的依赖;
org.aspectj
aspectjweaver
1.9.4
- ② 编写接口与实现类
public interface BookDao {
public void save();
public void update();
}
@Repository
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println(System.currentTimeMillis());
System.out.println("book dao save ...");
}
public void update(){
System.out.println("book dao update ...");
}
}
- ③ 创建Spring配置类
@Configuration
@ComponentScan("com.stone")
public class SpringConfig {
}
- ④ 编写运行类
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = ctx.getBean(BookDao.class);
bookDao.save();
}
}
2、AOP实现
- ① 定义通知类和通知 Advice
public class MyAdvice {
public void method(){
System.out.println(System.currentTimeMillis());
}
}
- ② 定义切入点 Pointcut
//设置切入点,要求配置在方法上方
@Pointcut("execution(void com.stone.dao.BookDao.update())")
private void pt(){}
- ③ 制作切面 Aspect
我们知道切面是用于描述通知Advice与切入点Pointcut的关系,此处我们在通知Advice上使用@Before注解,描述"pt()"与method通知的关系,如下:
//设置在切入点pt()的前面运行当前操作(前置通知)
@Before("pt()")
public void method(){
System.out.println(System.currentTimeMillis());
}
- ④ 将通知类配置给Context容器并标识为切面类
在我们的通知类上添加@Component注解和@Aspect注解,如下:
@Component
@Aspect
public class MyAdvice {
... ...
}
- ⑤ 开启注解格式AOP功能
在我们的配置类上添加@EnableAspectJAutoProxy注解,开启注解格式AOP功能,如下:
@Configuration
@ComponentScan("com.stone")
@EnableAspectJAutoProxy //开启注解格式AOP功能
public class SpringConfig {
}
- ⑥ 测试
3、总结
- ① 相关注解
@EnableAspectJAutoProxy:用于配置类上,开启注解格式AOP功能;
@Aspect:用于切面类上,设置当前类为AOP切面类;
@Pointcut:用于切点空方法上,设置切入点方法;
@Before、@After、@Around、@AfterReturning、@AfterThrowing:用于通知方法上方,设置当前通知方法与切入点之间绑定关系。
- ② 切入点表达式
切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数) 异常名)
*
:单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现;
..
:多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写;
+
:专用于匹配子类类型。
三、AOP获取通知数据
1、JoinPoint
我们可以在对应的通知内传入参数JoinPoint,其可以帮助我们获取被增强方法所传递的参数,具体如下:
@Before("pt()")
public void method(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
}
- ① 测试
Ⅰ 准备接口及实现类
public interface BookDao {
public void update(String text);
}
@Repository
public class BookDaoImpl implements BookDao {
public void update(String text){
System.out.println("book dao update ..." + text);
}
}
Ⅱ 修改织入
a、切点表达式处添加了参数String类型;
b、通知方法内添加了参数获取与打印;
//通知类必须配置成Spring管理的bean
@Component
//设置当前类为切面类类
@Aspect
public class MyAdvice {
//设置切入点,要求配置在方法上方
@Pointcut("execution(void com.itheima.dao.BookDao.update(String))")
private void pt(){}
//设置在切入点pt()的前面运行当前操作(前置通知)
@Before("pt()")
public void method(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
System.out.println("args is: " + Arrays.toString(args));
System.out.println("before advice ..." );
}
}
Ⅲ 测试类测试
bookDao.update("Hello JoinPoint!");
- ② 总结
JoinPoint是非环绕通知采用的获取方式,如:@Before、@After。
2、ProceedingJoinPoint
环绕通知使用的是ProceedingJoinPoint,因为ProceedingJoinPoint是JoinPoint类的子类,所以对于ProceedingJoinPoint类中应该也会有对应的getArgs()
方法。
- ① 测试
Ⅰ 修改接口和实现类方法
此处我们添加了返回值的设置,如下:
public Integer update(String text); // 接口中
public Integer update(String text){ // 实现类中
System.out.println("book dao update ..." + text);
return 200;
}
Ⅱ 修改切点表达式
由于我们设置了返回值,此处修改表达式中的对应返回值部分,如下:
@Pointcut("execution(Integer com.itheima.dao.BookDao.update(String))")
Ⅲ 添加织入
Object result = joinPoint.proceed();相比于前者,ProceedingJoinPoint多了执行原方法的逻辑,而且可以获得返回值,如下:
@Around("pt()")
public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args = joinPoint.getArgs();
System.out.println("args is: " + Arrays.toString(args));
System.out.println("before advice ...");
Object result = joinPoint.proceed(args);
System.out.println(result); // 打印返回值
System.out.println("after advice ...");
return result;
}
Ⅲ 测试类测试
- ② 总结
ProceedingJoinPoint用于@Around环绕通知的情形。
3、获取通知数据的使用场景
如:对传入密码的或者其他字符串的统一去除首位空格的操作。
@Around("DataAdvice.servicePt()")
// @Around("servicePt()")这两种写法都对
public Object trimStr(ProceedingJoinPoint pjp) throws Throwable {
//获取原始方法的参数
Object[] args = pjp.getArgs();
for (int i = 0; i < args.length; i++) {
//判断参数是不是字符串
if(args[i].getClass().equals(String.class)){
args[i] = args[i].toString().trim();
}
}
//将修改后的参数传入到原始方法的执行中
Object ret = pjp.proceed(args);
return ret;
}
此通知中,我们就能实现对对应字符串进行trim操作。
四、结尾
以上即为Spring AOP基础使用的全部内容,感谢阅读。