Spring-AOP学习

Posted defender

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring-AOP学习相关的知识,希望对你有一定的参考价值。

1.AOP中的术语

【1】连接点(JoinPoint): UserDaoImpl实现类中所有的方法称为连接点(JoinPoint)

             save()方法

             update()方法

【2】切入点pointcut:拦截哪些个方法(对哪个方法做增强,save(),update())

【3】通知/增强advice:具体做什么功能。如记录日志

             五种通知类型。

【4】目标对象target:UserDaoImpl称为目标对象

【5】织入waving:过程,把通知/增强添加到目标对象,生成代理对象的过程

【6】代理proxy:生成代理对象

【7】切面aspect:切入点 + 通知的组合称为切面

             通知---->自定义编写

             切入点--->自定义配置

2.测试

需求:在save方法执行之前,不改变原码输入日志记录

 

相应的接口和实现类

1 //接口
2 public interface UserDao{
3      public void save();
4      public void update();    
5 }
1 //实现类
2 public class UserDao implements UserDao{
3   public void save(){
4     System.out.println("保存用户...");
5   }
6   public void update(){
7     System.out.println("修改用户...");
8   }
9 }

 

切面类

 1 /**
 2  * 【步骤1】定义切面类:切入点Pointcut + 通知Advice
 3  */
 4 public class MyAspectXml {
 5     /*
 6      * 【步骤1】定义切面类:切入点Pointcut + 通知Advice
 7      * 
 8      * 【步骤2】通知(具体的增强方法)
 9      * 通知类型
10      * 
11      * 【步骤3】配置applicationContext.xml文件 
12      * 
13      * 【步骤4】<!-- 编写切面类配置 --> <bean id="myAspectXml" class="com.hl.aspects.MyAspectXml" />
14      * 
15      * 【步骤5】<!-- 配置AOP --> 
16      *         <aop:config> 
17      *         【步骤6】<!-- 配置切面类:切入点 + 通知 (类型)--> 
18      *             <aop:aspect ref="myAspectXml">
19      *          【步骤7】<!-- 配置的前置通知,save方法执行之前,增强的方法会执行 -->
20      *              <!--切入点的表达式:execution(public void com.hl.impl.CustomerDaoImpl.save()) -->
21      *                 <aop:before method="log" pointcut="execution(public void com.hl.impl.CustomerDaoImpl.save())"/>
22      *             </aop:aspect>
23      *         </aop:config>
24      */
25     
26     //通知(具体的增强)
27     public void log(){
28         System.out.println("记录日志...");
29     }
30     
31     /*
32      * 最终通知:方法执行成功或出现异常,都会执行
33      */
34     public void after(){
35         System.out.println("最终通知...");
36     }
37     
38     /*
39      * 后置通知:执行后通知,程序出现了异常后,后置通知不会执行的 
40      * 
41      */
42     public void afterReturn(){
43         System.out.println("后置通知...");
44     }
45     
46     /*
47      * 环绕通知:方法执行之前和方法执行之后进行通知,默认情况下,目标对象的方法是不能执行的。需手动让目标对象的方法执行。 
48      * 
49      */
50     public void around(ProceedingJoinPoint joinPoint){
51         System.out.println("环绕通知1...");
52         
53         //手动让目标对象的方法去执行,常用于事务管理
54         try {
55             joinPoint.proceed();
56         } catch (Throwable e) {
57             e.printStackTrace();
58         }
59         
60         System.out.println("环绕通知2...");
61     }   
66 }

 

配置文件applicationContext.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xmlns:context="http://www.springframework.org/schema/context"
 5     xmlns:aop="http://www.springframework.org/schema/aop"
 6     xmlns:tx="http://www.springframework.org/schema/tx"
 7     xsi:schemaLocation="http://www.springframework.org/schema/beans 
 8     http://www.springframework.org/schema/beans/spring-beans.xsd
 9     http://www.springframework.org/schema/context
10     http://www.springframework.org/schema/context/spring-context.xsd
11     http://www.springframework.org/schema/aop
12     http://www.springframework.org/schema/aop/spring-aop.xsd
13     http://www.springframework.org/schema/tx 
14     http://www.springframework.org/schema/tx/spring-tx.xsd">
15     
16     <!-- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
17     xmlns:aop="http://www.springframework.org/schema/aop" 
18     xmlns:context="http://www.springframework.org/schema/context" 
19     xsi:schemaLocation="http://www.springframework.org/schema/beans 
20         http://www.springframework.org/schema/beans/spring-beans.xsd
21         http://www.springframework.org/schema/aop 
22         http://www.springframework.org/schema/aop/spring-aop.xsd
23         http://www.springframework.org/schema/context 
24         http://www.springframework.org/schema/context/spring-context.xsd">  -->
25          <!-- bean definitions here -->
26     <!-- 配置客户的dao -->
27     <bean id="customerDao" class="com.hl.service.impl.CustomerDaoImpl"></bean>
28     
29     <!-- 【步骤4】编写切面类配置 -->
30     <bean id="myAspectXml" class="com.hl.aspects.MyAspectXml" />
31     
32     <!-- 配置AOP -->
33     <aop:config>
34         <!-- 配置切面类:切入点 + 通知 (类型)-->
35         <aop:aspect ref="myAspectXml">
36          
37             <!-- 配置的前置通知,save方法执行之前,增强的方法会执行 -->
38             <!-- 1. 前置通知 -->
39             <aop:before method="log" pointcut="execution(public void com.hl.service.impl.CustomerDaoImpl.save(..))"/>
40             
41             <!-- 2. 最终通知 -->
42             <!-- <aop:after method="after" pointcut-ref="execution(public void com.hl.impl.CustomerDaoImpl.save(..))"/> -->
43             
44             <!-- 3. 后置通知 -->
45             <!-- <aop:after-returning method="afterReturnning" pointcut-ref="execution(public void com.hl.impl.CustomerDaoImpl.save(..))"/> -->
46             
47             <!-- 4. 异常抛出通知 -->
48             
49             <!-- 5. 环绕通知 -->
50             <!-- <aop:around method="around" pointcut-ref="execution(public void com.hl.impl.CustomerDaoImpl.save(..))"/> -->
51             
52             <!-- 切入点的表达式:execution(public void com.hl.impl.CustomerDaoImpl.save()) -->
53             <!-- 切入点的表达式
54                 1.execution() 固定的,不能省略
55                 
56                 2.public 可省略不写
57                 <aop:before method="log" pointcut="execution(void com.hl.impl.CustomerDaoImpl.save(..))"/>
58                 
59                 3.void 返回值类型可以出现*号,表示任意的返回值,返回值类型不能不写
60                 <aop:before method="log" pointcut="execution(* com.hl.impl.CustomerDaoImpl.save(..))"/>
61                 
62                 4.包名可使用*代替,不能省略,简写方式:*..*方法
63                 <aop:before method="log" pointcut="execution(* com.hl.*.CustomerDaoImpl.save(..))"/>
64                 
65                 包的简写方式,任意的包的结构
66                 <aop:before method="log" pointcut="execution(* *..*.CustomerDaoImpl.save(..))"/>
67                 
68                 5.*DaoImpl,包名以DaoImpl结尾的
69                 编写类的写法
70                 <aop:before method="log" pointcut="execution(* *..*.*DaoImpl.save(..))"/>
71                 
72                 6.方法save*
73                 方法的编写
74                 <aop:before method="log" pointcut="execution(* *..*.*DaoImpl.save*())"/>
75                 
76                 7.方法的参数:..表示任意的参数
77                 参数列表:出现一个*,表示一个参数;任意参数使用..
78                 <aop:before method="log" pointcut="execution(void com.hl.impl.CustomerDaoImpl.save*())"/>
79                 <aop:before method="log" pointcut="execution(void com.hl.impl.CustomerDaoImpl.save*(..))"/>
80              -->
81             
82         </aop:aspect>
83     </aop:config>
84 </beans>

 

3.小结

实现类中重写接口方法,UserDaoImpl实现类中所有的方法即连接点。

在不改变原码而增加需求时,可定义与实现类平级的切面类,即目标类的切入点(目标类中的所有方法)和增强/通知(新增功能)来定义切面类。

关于xml配置文件,则是常规的配置方式:

配置切面类bean

配置AOP----配置(类切入点和通知)-----配置通知类型

 

以上是关于Spring-AOP学习的主要内容,如果未能解决你的问题,请参考以下文章

Spring-AOP学习

spring框架学习6:spring-aop的五种通知类型

Spring-AOP学习笔记-04 注解配置

Spring-AOP学习笔记-01 初识AOP

Spring-AOP学习笔记-03通知

Spring-AOP