1.AOP的概念
AOP,Aspect Oriented Programming,面向切面编程,是对面向对象编程OOP的升华。OOP是纵向对一个 事物的抽象,一个对象包括静态的属性信息,包括动态的方法信息等。而AOP是横向的对不同事物的抽象,属 性与属性、方法与方法、对象与对象都可以组成一个切面,而用这种思维去设计编程的方式叫做面向切面编程。
2.基于xml配置的AOP
- xml方式AOP快速入门 通过配置文件的方式去解决上述问题
- 配置哪些包、哪些类、哪些方法需要被增强
- 配置目标方法要被哪些通知方法所增强,在目标方法执行之前还是之后执行增强
- 配置方式的设计、配置文件(注解)的解析工作,Spring已经帮我们封装好了
2.1xml方式配置AOP的步骤:
1、导入AOP相关坐标;
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.19</version>
<scope>runtime</scope>
</dependency>
2、准备目标类、准备增强类,并配置给Spring管理;
public interface UserService {
void show1();
void show2();
}
public class UserServiceImpl implements UserService {
public void show1() {
System.out.println("show1...");
}
public void show2() {
System.out.println("show2...");
}
}
public class MyAdvice {
public void beforeAdvice(){
System.out.println("beforeAdvice");
}
public void afterAdvice(){
System.out.println("afterAdvice");
}
}
<!--配置目标类,内部的方法是连接点-->
<bean id="userService" class="com.fly.service.Impl.UserServiceImpl"></bean>
<!--配置通知类,内部的方法是增强方法-->
<bean id="myProxy" class="com.fly.proxy.MyAdvice"></bean>
3、配置切点表达式(哪些方法被增强);
4、配置织入(切点被哪些通知方法增强,是前置增强还是后置增强)
<aop:config>
<!--配置切点表达式,对哪些方法进行增强-->
<aop:pointcut id="pointcut01" expression="execution(void com.fly.service.Impl.UserServiceImpl.show1())"/><!--切面=切点+通知-->
<aop:aspect ref="myProxy"><--指定前置通知方法是beforeAdvice-->
<aop:before method="beforeAdvice" pointcut-ref="pointcut01"/>< !--指定后置通知方法是afterAdvice-->
<aop:after-returning method="afterAdvice" pointcut-ref="pointcut01"></aop:after-returning>
</aop:aspect>
</aop:config>
2.2XML方式AOP配置详解
XML方式配置AOP还是比较简单的,下面看一下AOP配置的详细细节
-
切点表达式的配置方式
-
切点表达式的配置语法
-
通知的类型
2.2.1切点表达式的配置方式
切点表达式的配置方式有两种,直接将切点表达式配置在通知上,也可以将切点表达式抽取到外面,在通知上进行引用
2.2.2切点表达式的配置语法
切点表达式是配置要对哪些连接点(哪些类的哪些方法)进行通知的增强,语法如下:
execution([访问修饰符] 返回值类型 包名.类名.方法名(参数))
其中:
-
访问修饰符可以省略不写;
-
返回值类型,某一级包名,类名,方法名 可以使用*表示任意;
-
包名与类名之间使用单点
.
表示该包下的类,使用双点..
表示该包及其子包下的类; -
参数列表可以使用两个点
..
表示任意参数
<aop:pointcut id="pointcut01" expression="execution(void com.fly.service..UserServiceImpl.show1())"/>
表示service包及其子包下面的show1方法。
参数列表两个点表示任意的参数个数
<aop:pointcut id="pointcut01" expression="execution(void com.fly.service..UserServiceImpl.show1(..))"/>
切点表达式举几个大家容易理解的例子
//表示访问修饰符为public、无返回值、在com.fly.aop包下的TargetImpl类的无参方法show execution(public void com.fly.aop.TargetImpl.show())
//表述com.fly.aop包下的TargetImpl类的任意方法
execution(* com.fly.aop.TargetImpl.*(..))
//表示com.fly.aop包下的任意类的任意方法
execution(* com.fly.aop.*.*(..))
//表示com.fly.aop包及其子包下的任意类的任意方法
execution(* com.fly.aop..*.*(..))
//表示任意包中的任意类的任意方法 execution(* *..*.*(..))
2.2.3:通知的类型
AspectJ的通知由以下五种类型
通知名称 | 配置方式 | 执行时机 |
---|---|---|
前置通知 | <aop:before> | 目标方法执行之前执行 |
后置通知 | <aop:after-returning> | 目标方法执行之后,目标方法异常时,不在执行 |
环绕通知 | <aop:around> | 目标方法执行前后执行,目标方法异常时,环绕后方法不在执行 |
异常通知 | <aop:after-throwing> | 目标方法抛出异常时执行 |
最终通知 | <aop:after> | 不管目标方法是否有异常,最终都会执行 |
<?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
">
<!--1:先将相关的两个对象配置到容器中,常规配置-->
<bean id="userService" class="com.fly.service.impl.UserServiceImpl"/>
<bean id="myAdvice" class="com.fly.proxy.MyAdvice"/>
<aop:config>
<aop:aspect ref="myAdvice">
<!--1:方法的参数 用两个.来代替 ..只有方法有参数都是用两个点来替代-->
<!-- <aop:before method="beforeShow" pointcut="execution(int com.fly.service.impl.UserServiceImpl.show4(..))"></aop:before>-->
<!--2:包名的省略 使用* 当前包下面或者当前包子包下面查找-->
<aop:before method="beforeShow" pointcut="execution(int com.fly..show4(..))"/>
<aop:after-returning method="beforeShow" pointcut="execution(int com.fly..show4(..))"/>
<!--环绕通知-->
<aop:around method="aroundShow" pointcut="execution(int com..show4(..))"/>
<!--目标方法出现错误的时候,执行这个方法-->
<aop:after-throwing method="executionShow" pointcut="execution(int com..show4(..))"/>
<!--最终通知-->
<aop:after method="afterAshow" pointcut="execution(int com..show4(..))"/>
</aop:aspect>
</aop:config>
</beans>
package com.fly.proxy;
import org.aspectj.lang.ProceedingJoinPoint;
// 代理类
public class MyAdvice {
// 1:前置通知,目标方法之前执行这个通知
public void beforeShow() {
System.out.println("在show方法之前执行");
}
//2: 后置通知,目标方法执行之后执行 (目标方法不能出现错误)出错就不走了
public void afterShow() {
System.out.println("在show方法之后执行");
}
//3: 环绕通知
public Object aroundShow(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object[] args = proceedingJoinPoint.getArgs();
System.out.println(args.length);
System.out.println("环绕通知之前");
//show4()
Object proceed = proceedingJoinPoint.proceed(args);
System.out.println("环绕通知之后");
return proceed;
}
//4:在目标方法抛出异常的时候执行
public void exeptionShow(){
System.out.println("目标方法抛出异常的时候执行");
}
//5.最终通知方法
public void afterAshow(){
System.out.println("Good Good");
}
}