第四章 面向切面的Spring

4.1 什么是面向切面编程

  横切关注点可以被模块化为特殊的类,这些类被称为切面。

  好处:1关注点集中在一处,不是分散在多处代码中;2服务(主要的业务)模块更简洁,他们只包含主要关注点(或核心功能)的代码,次要关注点的代码被转移到切面中了;

4.1.1 定义AOP术语

  术语:通知(advice),切点(pointcut)和连接点(join point);

  

  通知(advice)定义了切面是什么以及何时使用(定义切面是“什么”及“何时”)。

  • Before——在方法被调用之前调用通知
  • After——在方法完成之后
  • after-returning——在方法成功执行之调用通知
  • after-throwing——在方法抛出异常后调用通知
  • Around——通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。

 连接点(Joinpoint):是在应用执行过程中能够插入切面的一个点。这个点可以是调用的方法时,抛出异常时,修改一个字段时(是一个时机),切面代码可以利用这些点插入到应用的正常流程之中,添加新的行为。

  切点(Pointcut):匹配通知所要织入的一个或多个连接点(定义切面在“何处”)

    切面(Aspect):是通知和切点的结合,通知和切点共同定义了关于切面的全部内容——是什么,何时、何处完成其功能;

  织入(Weaving):是将切面引用到目标对象来创建新的dialing对象的过程,切面在指定的连接点被织入到目标对象中。在目标对象的生命周期中有多个点可以进行织入。

  • 编译期——切面在目标类编译时被织入。这种方式需要特殊的编译器。AspectJ的织入编译期就是以这种方式织入切面的。
  • 类加载期——切面子啊目标被加载到JVM时被织入。这种方式需要特殊的类加载器(ClassLoader),它可以在目标类被引入引用之前增强该目标类的字节码。AspectJ5的LTW(load-time weaving)就支持以这种方式织入。
  • 运行期——切面在应用运行的某个时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态地创建一个代理对象。SpringAOP就是以这种方式织入切面的

4.1.2 Spring对AOP的支持

  spring提供了4中AOP支持:

  • 基于代理的经典AOP(这本书中不介绍);
  • @AspectJ注解驱动的切面
  • 纯POJO切面
  • 注入式AspectJ切面(适合spring个版本)

  前三种都是Spring基于代理的AOP变体,因此Spring对AOP的支持局限于方法拦截。若是AOP需求超过了简单方法的拦截的范凑,那么考虑在AspectJ里实现切面,利用Spring的DI把Spring Bean注入到AspectJ切面中。

4.2 使用切点选择连接点

  略过。。。

4.3 在xml中声明切面

4.3.1 声明前置通知和后置通知

  声明切面,我们先创建一个观众的Audience切面类:

 1 package com.springinaction.springidol;
 2 
 3 /**
 4  * 
 5  * @ClassName: Audience 
 6  * @Description: 观众的切面类
 7  * @author mao
 8  * @date 2017年3月23日 下午4:07:01 
 9  *
10  */
11 public class Audience {
12     
13     public void takeSeats(){
14         //表演之前
15         System.out.println("观众开始入座!");
16     }
17     
18     public void turnOffCellPhones(){
19         //表演之前
20         System.out.println("观众正在坐着");
21     }
22     
23     public void applaud(){
24         //表演之后
25         System.out.println("表演完后,鼓掌!鼓掌!鼓掌!");
26     }
27     
28     public void demandRefund(){
29         //表演失败之后
30         System.out.println("表演失败,我们要退钱!");
31     }
32     
33     
34     
35 }
View Code

  首先,pom.xml文件中引入spring.aspects.jar文件

1 <!-- spring aspects依赖,AOP用到 -->
2  <dependency>
3       <groupId>org.springframework</groupId>
4       <artifactId>spring-aspects</artifactId>
5       <version>4.2.9.RELEASE</version>
6 </dependency>
View Code

  其次,springbean.xml文件中<beans>标签中需要引入aop的命名空间 :xmlns:aop="http://www.springframework.org/schema/aop" 和xsi:schemaLocation="
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"

 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:p="http://www.springframework.org/schema/p"
 7     xsi:schemaLocation="http://www.springframework.org/schema/beans 
 8         http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
 9         http://www.springframework.org/schema/context
10         http://www.springframework.org/schema/context/spring-context-4.0.xsd
11         http://www.springframework.org/schema/aop 
12         http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
13     
14      
15      <!--观众的bean  -->
16      <bean id="audience"
17              class="com.springinaction.springidol.Audience"></bean>
18      <context:component-scan 
19         base-package="com.springinaction.springidol"></context:component-scan>
20      
21      <!-- 声明aop -->
22      <!-- 
23           <aop:config>顶层的AOP配置元素,大多数<aop:*>都包在这个元素内
24       -->
25      <aop:config>
26          <!-- 引用audience Bean
27              <aop:aspect>定义切面的元素
28           -->
29          <aop:aspect ref="audience">
30              
31              <!-- 表演之前 -->
32              <!-- <aop:before>定义aop前置通知 
33                  pointcut=""是切点表达式,和method=""一起用,告诉通知切点在哪
34                  整个标签表达出 在哪个类的那个方法执行什么通知
35              -->
36              <aop:before 
37                  pointcut="execution(* com.springinaction.springidol.Performer.perform(..))" method="takeSeats"/>
38              
39              <!-- 表演之后  --> 
40             <aop:before 
41                 pointcut="execution(* com.springinaction.springidol.Performer.perform(..))"
42                  method="turnOffCellPhones"/>             
43              
44              <!-- 表演之后 -->
45              <!-- <aop:after-returning>定义aop返回通知 -->
46              <aop:after-returning
47                 pointcut="execution(* com.springinaction.springidol.Performer.perform(..))"
48                  method="applaud"/>             
49              
50              <!-- 表演失败之后 -->
51              <!-- <aop:after-throwing>定义aop异常通知 -->
52              <aop:after-throwing 
53                 pointcut="execution(* com.springinaction.springidol.Performer.perform(..))"
54                  method="demandRefund"/>            
55          
56          </aop:aspect>
57      </aop:config>
58     
59      
60      
61      
62     
63 </beans>
View Code
 1 package com.springinaction.springidol;
 2 
 3 import javax.inject.Inject;
 4 
 5 import javax.inject.Named;
 6 
 7 import org.springframework.beans.factory.annotation.Autowired;
 8 import org.springframework.beans.factory.annotation.Qualifier;
 9 import org.springframework.beans.factory.annotation.Value;
10 import org.springframework.stereotype.Component;
11 
12 
13 
14 /**
15  * 
16 * @ClassName: Instrumentalist 
17 * @Description: 一个有天赋的音乐家
18 * @author mao
19 * @date 2017年3月19日 下午7:15:17 
20 *
21  */
22 //将该类注册到Spring容器中,显示的为其命名为kenny。即ID为kenny
23 @Component("kenny")
24 public class Instrumentalist implements Performer {
25     
26     @Value("演员---薛之谦")
27     private String song;
28     
29     @Autowired
30     @Qualifier("saxophone")
31     private Instrument instrument;
32     
33     //注入乐器
34     public void setInstrument(Instrument instrument) {
35         this.instrument = instrument;
36     }
37     public Instrument getInstrument() {
38         return instrument;
39     }
40     //注入歌曲
41     public void setSong(String song) {
42         this.song = song;
43     }
44     public String getSong() {
45         return song;
46     }
47     
48     public Instrumentalist(){
49         
50     }
51 
52     public void perform() throws Exception {
53 //        int i = 3/0;
54         System.out.println("Playing "+song+": ");
55     }
56 
57 }
View Code

测试:

 1 package com.springinaction.test;
 2 
 3 import org.junit.Test;
 4 
 5 
 6 import org.springframework.context.ApplicationContext;
 7 import org.springframework.context.support.ClassPathXmlApplicationContext;
 8 
 9 import com.springinaction.springidol.Auditorium;
10 import com.springinaction.springidol.Instrumentalist;
11 import com.springinaction.springidol.OneManBand;
12 import com.springinaction.springidol.Performer;
13 import com.springinaction.springidol.PoeticJuggler;
14 import com.springinaction.springidol.Stage;
15 import com.springinaction.springidol.Ticket;
16 
17 
18 public class TestCase {
19     
20     //这个ClassPathXmlApplicationContext是springframe-context中
21     //org.springframework.context.support包下的类
22     ApplicationContext ac = new ClassPathXmlApplicationContext("spring/springbean.xml");//注意路径
23     
24     //测试声明式的切面、通知
25     @Test
26     public void testAspect() throws Exception {
27         
28         Performer kenny = (Performer) ac.getBean("kenny");
29 //        System.out.println(kenny);
30          
31         kenny.perform();//输出 Playing 演员——薛之谦: 
32 
33         
34         
35     }
36 
37     
38 }
View Code

结果:

测试异常通知在Instrumentalist 的perform()方法中的int i=3/0注释解封,结果:

这里要注意的是,这里的aop使用的是JDK的动态代理,因为Instrumentalist是实现了Perfromer的类,这个是JDK动态代理的条件吧,spring AOP还有个cglib代理,这个是通过创建一个类的子类来获得一个代理(这个子类是底层完成的),两者有区别,这里不详细说了(默认是使用JDK动态代理,若是满足不了JDK动态代理的条件,那就启用cglib代理)。

   上述的springbean.xml的aop配置还可以如下配置,简化一下代码:

 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:p="http://www.springframework.org/schema/p"
 7     xsi:schemaLocation="http://www.springframework.org/schema/beans 
 8         http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
 9         http://www.springframework.org/schema/context
10         http://www.springframework.org/schema/context/spring-context-4.0.xsd
11         http://www.springframework.org/schema/aop 
12         http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
13     
14      
15      <!--观众的bean  -->
16      <bean id="audience"
17              class="com.springinaction.springidol.Audience"></bean>
18      <!--注解形式的 组件扫描 -->
19      <context:component-scan 
20         base-package="com.springinaction.springidol"></context:component-scan>
21      
22      <!-- 声明aop -->
23      <!-- 
24           <aop:config>顶层的AOP配置元素,大多数<aop:*>都包在这个元素内
25       -->
26     <!--  <aop:config>
27          引用audience Bean
28              <aop:aspect>定义切面的元素
29          
30          <aop:aspect ref="audience">
31              
32              表演之前
33              <aop:before>定义aop前置通知 
34                  pointcut=""是切点表达式,和method=""一起用,告诉通知切点在哪
35                  整个标签表达出 在哪个类的那个方法执行什么通知
36              
37              <aop:before 
38                  pointcut="execution(* com.springinaction.springidol.Performer.perform(..))" method="takeSeats"/>
39              
40              表演之后  
41             <aop:before 
42                 pointcut="execution(* com.springinaction.springidol.Performer.perform(..))"
43                  method="turnOffCellPhones"/>             
44              
45              表演之后
46              <aop:after-returning>定义aop返回通知
47              <aop:after-returning
48                 pointcut="execution(* com.springinaction.springidol.Performer.perform(..))"
49                  method="applaud"/>             
50              
51              表演失败之后
52              <aop:after-throwing>定义aop异常通知
53              <aop:after-throwing 
54                 pointcut="execution(* com.springinaction.springidol.Performer.perform(..))"
55                  method="demandRefund"/>            
56          
57          </aop:aspect>
58      </aop:config> -->
59     
60      <!-- 上面配置aop的切点表达式是一样的,所以可以写成如下配置 -->
61      <aop:config>
62          <!-- 引用audience Bean -->
63          <aop:aspect ref="audience">
64              <!-- 定义切点表达式 -->
65              <aop:pointcut id="performance" expression="execution(* com.springinaction.springidol.Performer.perform(..))" />
66              <!-- 表演之前-->
67             <aop:before 
68                 pointcut-ref="performance"
69                  method="takeSeats"/>
70              <!-- 表演之前-->
71             <aop:before 
72                 pointcut-ref="performance"
73                  method="turnOffCellPhones"/>             
74              <!-- 
75              表演之后
76              <aop:after-returning>定义aop返回通知 -->
77              <aop:after-returning
78                 pointcut-ref="performance"
79                  method="applaud"/>             
80              
81              <!-- 表演失败之后
82              <aop:after-throwing>定义aop异常通知 -->
83              <aop:after-throwing 
84                 pointcut-ref="performance"
85                  method="demandRefund"/>            
86          
87          </aop:aspect>
88      </aop:config>
89      
90     
91 </beans>
View Code

4.3.2 声明环绕通知

在Audience类中增加如下的方法:

 1 //环绕通知
 2     public void watchPerformance(ProceedingJoinPoint joinpoint){
 3         try {
 4             System.out.println("观众正在坐在自己的位置上---表演之前");
 5             System.out.println("观众关闭他们的手机---表演之前");
 6             long start = System.currentTimeMillis();
 7             
 8             joinpoint.proceed();
 9             
10             long end=System.currentTimeMillis();
11             
12             System.out.println("表演很精彩,大家鼓掌....");
13             System.out.println("表演耗时:"+(end-start)+"毫秒");
14             
15         } catch (Throwable e) {
16             //表演失败,
17             System.out.println("太糟糕了,我们要退钱!");
18         }
19         
20         
21     }
View Code
 1 <!-- 上面配置aop的切点表达式是一样的,所以可以写成如下配置 -->
 2      <aop:config>
 3          <!-- 引用audience Bean -->
 4          <aop:aspect ref="audience">
 5              <!-- 定义切点表达式 -->
 6              <aop:pointcut id="performance" expression="execution(* com.springinaction.springidol.Performer.perform(..))" />
 7              <!-- 表演之前-->
 8             <!-- <aop:before 
 9                 pointcut-ref="performance"
10                  method="takeSeats"/> -->
11              <!-- 表演之前-->
12             <!-- <aop:before 
13                 pointcut-ref="performance"
14                  method="turnOffCellPhones"/>     -->         
15              <!-- 
16              表演之后
17              <aop:after-returning>定义aop返回通知 -->
18              <!-- <aop:after-returning
19                 pointcut-ref="performance"
20                  method="applaud"/>      -->        
21              
22              <!-- 表演失败之后
23              <aop:after-throwing>定义aop异常通知 -->
24              <!-- <aop:after-throwing 
25                 pointcut-ref="performance"
26                  method="demandRefund"/>     -->        
27              
28              <!-- 环绕通知 
29                  将其他通知都注释
30              -->
31              <aop:around 
32                  pointcut-ref="performance"
33                  method="watchPerformance"/>
34          </aop:aspect>
35      </aop:config>
View Code

 为了看出表演耗时的时间,在perform()方法中加Thread.sleep(1000)(加不加无所谓的)睡1秒;

结果:

4.3.3 为通知传递参数

  直接上一个读心者的例子,先创建几个类:

 1 package com.springinaction.springidol;
 2 
 3 /**
 4  * 读心者类
 5  * @ClassName: MindReader 
 6  * @Description: 可以读取别人的思想
 7  * @author mao
 8  * @date 2017年3月23日 下午5:23:49 
 9  *
10  */
11 public interface MindReader {
12     
13     //拦截别人的想法(感应别人的内心想法)
14     void interceptThoughts(String thoughts);
15     
16     //获得想法
17     String getThoughts();
18 }
View Code
 1 package com.springinaction.springidol;
 2 
 3 /**
 4  * 读心者的实现类
 5  * @ClassName: Magician 
 6  * @Description: 可以读取别人想法的具体实例
 7  * @author mao
 8  * @date 2017年3月23日 下午5:29:12 
 9  *
10  */
11 public class Magician implements MindReader {
12     
13     
14     private String thoughts;
15     
16     public void interceptThoughts(String thoughts) {
17         
18         System.out.println("感应志愿者的想法!");
19         this.thoughts = thoughts;
20 
21     }
22 
23     public String getThoughts() {
24         
25         return thoughts;
26     }
27 
28 }
View Code
 1 package com.springinaction.springidol;
 2 
 3 /**
 4  * 思考者的接口
 5  * @ClassName: Thinker 
 6  * @Description: 沉思者 
 7  * @author mao
 8  * @date 2017年3月23日 下午5:30:07 
 9  *
10  */
11 public interface Thinker {
12     //瞎想
13     void thinkOfSomething(String thoughts);
14 }
View Code
 1 package com.springinaction.springidol;
 2 
 3 /**
 4  * 沉思者
 5  * @ClassName: Volunteer 
 6  * @Description: 一个时代的思想家
 7  * @author mao
 8  * @date 2017年3月23日 下午5:31:58 
 9  *
10  */
11 public class Volunteer implements Thinker {
12     
13     private String thoughts;
14     
15     public void thinkOfSomething(String thoughts) {
16         
17         this.thoughts = thoughts;
18 
19     }
20 
21     public String getThoughts() {
22         return thoughts;
23     }
24     
25 }
View Code

xml的配置(晕倒,在切点表达式中把thoughts写错了,找了老半天的错误) arg()限制连接点匹配参数为指定类型的执行方法:

  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:p="http://www.springframework.org/schema/p"
  7     xsi:schemaLocation="http://www.springframework.org/schema/beans 
  8         http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
  9         http://www.springframework.org/schema/context
 10         http://www.springframework.org/schema/context/spring-context-4.0.xsd
 11         http://www.springframework.org/schema/aop 
 12         http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
 13     
 14      
 15      <!--观众的bean  -->
 16     <bean id="audience"
 17              class="com.springinaction.springidol.Audience"></bean>
 18      <!--注解形式的 组件扫描 -->
 19      <context:component-scan 
 20         base-package="com.springinaction.springidol"></context:component-scan>
 21      
 22      <!-- 声明aop -->
 23      <!-- 
 24           <aop:config>顶层的AOP配置元素,大多数<aop:*>都包在这个元素内
 25       -->
 26     <!--  <aop:config>
 27          引用audience Bean
 28              <aop:aspect>定义切面的元素
 29          
 30          <aop:aspect ref="audience">
 31              
 32              表演之前
 33              <aop:before>定义aop前置通知 
 34                  pointcut=""是切点表达式,和method=""一起用,告诉通知切点在哪
 35                  整个标签表达出 在哪个类的那个方法执行什么通知
 36              
 37              <aop:before 
 38                  pointcut="execution(* com.springinaction.springidol.Performer.perform(..))" method="takeSeats"/>
 39              
 40              表演之后  
 41             <aop:before 
 42                 pointcut="execution(* com.springinaction.springidol.Performer.perform(..))"
 43                  method="turnOffCellPhones"/>             
 44              
 45              表演之后
 46              <aop:after-returning>定义aop返回通知
 47              <aop:after-returning
 48                 pointcut="execution(* com.springinaction.springidol.Performer.perform(..))"
 49                  method="applaud"/>             
 50              
 51              表演失败之后
 52              <aop:after-throwing>定义aop异常通知
 53              <aop:after-throwing 
 54                 pointcut="execution(* com.springinaction.springidol.Performer.perform(..))"
 55                  method="demandRefund"/>            
 56          
 57          </aop:aspect>
 58      </aop:config> -->
 59      
 60      
 61      <!-- 上面配置aop的切点表达式是一样的,所以可以写成如下配置 -->
 62      <aop:config>
 63          <!-- 引用audience Bean -->
 64          <aop:aspect ref="audience">
 65              <!-- 定义切点表达式 -->
 66              <aop:pointcut id="performance" expression="execution(* com.springinaction.springidol.Performer.perform(..))" />
 67              <!-- 表演之前-->
 68             <!-- <aop:before 
 69                 pointcut-ref="performance"
 70                  method="takeSeats"/> -->
 71              <!-- 表演之前-->
 72             <!-- <aop:before 
 73                 pointcut-ref="performance"
 74                  method="turnOffCellPhones"/>     -->         
 75              <!-- 
 76              表演之后
 77              <aop:after-returning>定义aop返回通知 -->
 78              <!-- <aop:after-returning
 79                 pointcut-ref="performance"
 80                  method="applaud"/>      -->        
 81              
 82              <!-- 表演失败之后
 83              <aop:after-throwing>定义aop异常通知 -->
 84              <!-- <aop:after-throwing 
 85                 pointcut-ref="performance"
 86                  method="demandRefund"/>     -->        
 87              
 88              <!-- 环绕通知 
 89                  将其他通知都注释
 90              -->
 91              <aop:around 
 92                  pointcut-ref="performance"
 93                  method="watchPerformance"/>
 94          </aop:aspect> 
 95          
 96          <aop:aspect ref="magician">
 97              <aop:pointcut 
 98                  id="thinking"
 99                  expression="execution(* com.springinaction.springidol.Thinker.thinkOfSomething(String)) and args(thoughts)" />
100              
101              <aop:before 
102                  pointcut-ref="thinking" 
103                  method="interceptThoughts" 
104                  arg-names="thoughts"/>
105          
106          </aop:aspect>
107      </aop:config>
108      
109      <bean id="volunteer" class="com.springinaction.springidol.Volunteer"></bean>
110      <bean id="magician" class="com.springinaction.springidol.Magician"></bean>
111     
112 </beans>
View Code

测试代码:

 1 //测试传入参数的通知
 2     @Test
 3     public void testArgsAdvisor() throws Exception {
 4         
 5         //思考者,先思考
 6         Thinker volunteer = (Thinker) ac.getBean("volunteer");
 7         volunteer.thinkOfSomething("你猜我想啥?");
 8         
 9         //读心者 对他想的啥
10         MindReader magician = (MindReader) ac.getBean("magician");
11         System.out.println(magician.getThoughts());
12 
13     }
View Code

结果:

4.4 注解切面

 注解使用:

 1 package com.springinaction.springidol;
 2 
 3 import org.aspectj.lang.ProceedingJoinPoint;
 4 import org.aspectj.lang.annotation.After;
 5 import org.aspectj.lang.annotation.AfterReturning;
 6 import org.aspectj.lang.annotation.AfterThrowing;
 7 import org.aspectj.lang.annotation.Around;
 8 import org.aspectj.lang.annotation.Aspect;
 9 import org.aspectj.lang.annotation.Before;
10 import org.aspectj.lang.annotation.Pointcut;
11 import org.springframework.stereotype.Component;
12 
13 /**
14  * 
15  * @ClassName: Audience 
16  * @Description: 观众的切面类
17  * @author mao
18  * @date 2017年3月23日 下午4:07:01 
19  *
20  */
21 @Component//这个不要忘了,注解的自动扫描 会将其加入到IOC容器中
22 @Aspect
23 public class Audience {
24     
25     //定义一个可以在@AspectJ切面内可重用的切点
26     @Pointcut("execution(* com.springinaction.springidol.Performer.perform(..))")
27     public void performance(){
28         
29     }
30     
31     
32     @Before("performance()")
33     public void takeSeats(){
34         //表演之前
35         System.out.println("观众开始入座!");
36     }
37     
38     @Before("performance()")
39     public void turnOffCellPhones(){
40         //表演之前
41         System.out.println("观众正在坐着");
42     }
43     
44     @AfterReturning("performance()")
45     public void applaud(){
46         //表演之后
47         System.out.println("表演完后,鼓掌!鼓掌!鼓掌!");
48     }
49     
50     @AfterThrowing("performance()")
51     public void demandRefund(){
52         //表演失败之后
53         System.out.println("表演失败,我们要退钱!");
54     }
55     
56     //环绕通知
57     @Around("performance()")
58     public void watchPerformance(ProceedingJoinPoint joinpoint){
59         try {
60             System.out.println("观众正在坐在自己的位置上---表演之前");
61             System.out.println("观众关闭他们的手机---表演之前");
62             long start = System.currentTimeMillis();
63             
64             joinpoint.proceed();
65             
66             long end=System.currentTimeMillis();
67             
68             System.out.println("表演很精彩,大家鼓掌....");
69             System.out.println("表演耗时:"+(end-start)+"毫秒");
70             
71         } catch (Throwable e) {
72             //表演失败,
73             System.out.println("太糟糕了,我们要退钱!");
74         }
75         
76         
77     }
78     
79     
80 }
View Code
 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:p="http://www.springframework.org/schema/p"
 7     xsi:schemaLocation="http://www.springframework.org/schema/beans 
 8         http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
 9         http://www.springframework.org/schema/context
10         http://www.springframework.org/schema/context/spring-context-4.0.xsd
11         http://www.springframework.org/schema/aop 
12         http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
13     
14  
15      <!--注解形式的 组件扫描 -->
16      <context:component-scan 
17         base-package="com.springinaction.springidol"></context:component-scan>
18      <!--使用@AspectJ注解作为指引来创建给予代理的切面,就是把他编程切面,这个@AspectJ类中的有且点表达式和通知  -->
19     <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
20     
21     
22     
23 </beans>
View Code

测试结果(测试用例之前写过):

这本书中错误还不少,不过不妨碍阅读:<aop:aspectj-autoproxy> 红色写成了aespectj,还有前面有一个写环绕通知的时候,method="watchPerformance()";括弧是不需要的。

4.5 注入AspectJ切面

   表示看不懂。。。

 

源码下载地址

posted @ 2017-03-23 20:08  花雪依蒿  阅读(165)  评论(0)    收藏  举报