二、基于 XML 的 AOP 开发
2.1 简单操作
① 导入 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.8.4</version> </dependency>
② 创建目标接口和目标类(内部有切点)
public interface TargetInterface { public void method(); }
public class Target implements TargetInterface { @Override public void method() { System.out.println("Target running...."); } }
③ 创建切面类(内部有增强方法)
public class MyAspect { //前置增强方法 public void before(){ System.out.println("前置代码增强....."); } }
④ 将目标类和切面类的对象创建权交给 spring
<!--目标对象--> <bean id="target" class="com.itheima.aop.Target"/> <!--切面对象--> <bean id="myAspect" class="com.itheima.aop.MyAspect"/>
⑤ 在 applicationContext.xml 中配置织入关系
导入aop命名空间
<?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" xmlns:context="http://www.springframework.org/schema/context" 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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--配置织入:告诉spring框架 哪些方法(切点)需要进行哪些增强(前置、后置...)--> <aop:config> <!--声明切面--> <aop:aspect ref="myAspect"> <!--抽取切点表达式--> <aop:pointcut id="myPointcut" expression="execution(* com.itheima.aop.*.*(..))"></aop:pointcut> <!--切面:切点+通知--> <!--<aop:before method="before" pointcut="execution(public void com.itheima.aop.Target.save())"/>--> <!--<aop:before method="before" pointcut="execution(* com.itheima.aop.*.*(..))"/> <aop:after-returning method="afterReturning" pointcut="execution(* com.itheima.aop.*.*(..))"/>--> <!--<aop:around method="around" pointcut="execution(* com.itheima.aop.*.*(..))"/> <aop:after-throwing method="afterThrowing" pointcut="execution(* com.itheima.aop.*.*(..))"/> <aop:after method="after" pointcut="execution(* com.itheima.aop.*.*(..))"/>--> <aop:around method="around" pointcut-ref="myPointcut"/> <aop:after method="after" pointcut-ref="myPointcut"/> </aop:aspect> </aop:config> </beans>
⑥ 测试代码
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class AopTest { @Autowired private TargetInterface target; @Test public void test1(){ target.save(); } }
⑦ 测试结果
2.2 XML 配置 AOP 详解
1. 切点表达式的写法
表达式语法:
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
访问修饰符可以省略
返回值类型、包名、类名、方法名可以使用星号* 代表任意
包名与类名之间一个点 . 代表当前包下的类,两个点 … 表示当前包及其子包下的类
参数列表可以使用两个点 … 表示任意个数,任意类型的参数列表
例如:
execution(public void com.itheima.aop.Target.method()) execution(void com.itheima.aop.Target.*(..)) execution(* com.itheima.aop.*.*(..)) execution(* com.itheima.aop..*.*(..)) execution(* *..*.*(..))
2. 通知的类型
通知的配置语法:
<aop:通知类型 method=“切面类中方法名” pointcut=“切点表达式"></aop:通知类型>
名称 | 标签 | 说明 |
前置通知 | aop:before | 用于配置前置通知。指定增强的方法在切入点方法之前执行 |
后置通知 | aop:after-returning | 用于配置后置通知。指定增强的方法在切入点方法之后执行 |
环绕通知 | aop:around | 用于配置环绕通知。指定增强的方法在切入点方法之前和之后都执行 |
异常抛出通知 | aop:throwing | 用于配置异常抛出通知。指定增强的方法在出现异常时执行 |
最终通知 | aop:after | 用于配置最终通知。无论增强方式执行是否有异常都会执行 |
/
3. 切点表达式的抽取
当多个增强的切点表达式相同时,可以将切点表达式进行抽取,在增强中使用 pointcut-ref 属性代替 pointcut 属性来引用抽取后的切点表达式。
<aop:config> <!--引用myAspect的Bean为切面对象--> <aop:aspect ref="myAspect"> <aop:pointcut id="myPointcut" expression="execution(* com.itheima.aop.*.*(..))"/> <aop:before method="before" pointcut-ref="myPointcut"></aop:before> </aop:aspect> </aop:config>
2.3 知识要点
aop织入的配置
<aop:config> <aop:aspect ref=“切面类”> <aop:before method=“通知方法名称” pointcut=“切点表达式"></aop:before> </aop:aspect> </aop:config>
通知的类型:前置通知、后置通知、环绕通知、异常抛出通知、最终通知
切点表达式的写法:
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
三、基于注解的 AOP 开发
3.1 基本操作
① 创建目标接口和目标类(内部有切点)
public interface TargetInterface { public void method(); }
public class Target implements TargetInterface { @Override public void method() { System.out.println("Target running...."); } }
② 创建切面类(内部有增强方法)
public class MyAspect { //前置增强方法 public void before(){ System.out.println("前置代码增强....."); } }
③ 将目标类和切面类的对象创建权交给 spring
@Component("target") public class Target implements TargetInterface { @Override public void method() { System.out.println("Target running...."); } } @Component("myAspect") public class MyAspect { public void before(){ System.out.println("前置代码增强....."); } }
④ 在切面类中使用注解配置织入关系
@Component("myAspect") @Aspect public class MyAspect { @Before("execution(* com.itheima.aop.*.*(..))") public void before(){ System.out.println("前置代码增强....."); } }
⑤ 在配置文件中开启组件扫描和 AOP 的自动代理
<!--组件扫描--> <context:component-scan base-package="com.itheima.aop"/> <!--aop的自动代理--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
⑥ 测试代码
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class AopTest { @Autowired private TargetInterface target; @Test public void test1(){ target.method(); } }
⑦ 测试结果
3.2 注解配置 AOP 详解
1. 注解通知的类型
通知的配置语法:@通知注解(“切点表达式")
名称 | 注解 | 说明 |
前置通知 | @Before | 用于配置前置通知。指定增强的方法在切入点方法之前执行 |
后置通知 | @AfterReturning | 用于配置后置通知。指定增强的方法在切入点方法之后执行 |
环绕通知 | @Around | 用于配置环绕通知。指定增强的方法在切入点方法之前和之后都执行 |
异常抛出通知 | @AfterThrowing | 用于配置异常抛出通知。指定增强的方法在出现异常时执行 |
最终通知 | @After | 用于配置最终通知。无论增强方式执行是否有异常都会执行 |
2. 切点表达式的抽取
同 xml 配置 aop 一样,我们可以将切点表达式抽取。抽取方式是在切面内定义方法,在该方法上使用@Pointcut注解定义切点表达式,然后在在增强注解中进行引用。具体如下:
@Component("myAspect") @Aspect public class MyAspect { @Before("MyAspect.myPoint()") public void before(){ System.out.println("前置代码增强....."); } @Pointcut("execution(* com.itheima.aop.*.*(..))") public void myPoint(){} }
3.3 知识要点
注解aop开发步骤
① 使用@Aspect标注切面类
② 使用@通知注解标注通知方法
③ 在配置文件中配置aop自动代理aop:aspectj-autoproxy/
通知注解类型
前置通知 | @Before | 用于配置前置通知。指定增强的方法在切入点方法之前执行 |
后置通知 | @AfterReturning | 用于配置后置通知。指定增强的方法在切入点方法之后执行 |
环绕通知 | @Around | 用于配置环绕通知。指定增强的方法在切入点方法之前和之后都执行 |
异常抛出通知 | @AfterThrowing | 用于配置异常抛出通知。指定增强的方法在出现异常时执行 |
最终通知 | @After | 用于配置最终通知。无论增强方式执行是否有异常都会执行 |