当前位置: 移动技术网 > IT编程>开发语言>Java > 一起学Spring之注解和Schema方式实现AOP

一起学Spring之注解和Schema方式实现AOP

2019年10月27日  | 移动技术网IT编程  | 我要评论

概述

在上一篇,我们了解了通过实现接口和xml配置的方式来实现aop,在实现注解方式aop之前,先了解一下aspectj。aspectj是一个面向切面的框架,它扩展了java语言,定义了aop语法,能够在编译时实现代码的注入。spring通过集成apsectj实现了以注解方式定义通知类,大大减少了配置文件的工作量。本文主要讲解通过注解方式和schema方式实现aop编程,仅供学习分享使用,如有不足之处,还请指正。

实现aop的三种方式:

  1. 通过实现相应接口,并配置xml进行实现,可以参考上一篇。
  2. 通过注解方式实现。
  3. 通过schema的方式实现。

通过注解方式实现aop

@aspect 放在类的上面,表示这个类在spring容器中是一个切点注入类。

@component("logannotation") 表示此类是一个bean,在spring ioc容器里面进行注入。

步骤如下:

1. 定义一个类,并在类上面增加@aspect注解,表名此类为切面通知类。

如下所示:

 1 package com.hex.second;
 2 
 3 import org.aspectj.lang.joinpoint;
 4 import org.aspectj.lang.proceedingjoinpoint;
 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.springframework.stereotype.component;
11 
12 /**
13  * @aspect:声明类为一个通知类
14  * @component("logannotation"):通过注解方法生成一个bean,但是需要配置注解的支持
15  * 通过注解的方式声明通知
16  * @author administrator
17  *
18  */
19 @component("logannotation")
20 @aspect
21 public class logaspectannotation {
22 
23 }

2. 前置通知函数

@before("execution(public void com.hex.second.studentserviceimpl.addstudent(com.hex.second.student))") 表示前置通知,用两个参数,默认为value值,指示切入点,告诉spring在哪些地方进行注入。

joinpoint 可以获取切入点的所有内容,包括目标对象,函数名称,参数,返回值等等。如下所示:

1 /**
2  * 前置通知,@before的参数为目标通知类的表达式
3  * joinpoint 用来获取目标函数的参数及对象等信息
4  */
5 @before("execution(public void com.hex.second.studentserviceimpl.addstudent(com.hex.second.student))")
6 public void mybefore(joinpoint jp){
7     system.out.println("我是注解方式的前置通知");
8     system.out.println("method="+jp.getsignature().getname()+",args数量="+jp.getargs().length+",target="+jp.gettarget());
9 }

3. 后置通知

@afterreturning(pointcut = "execution(public void com.hex.second.studentserviceimpl.addstudent(com.hex.second.student))",returning="returningvalue") 表示后置通知,其中value和poingcut都表示切入点,功能一样。returning表示定义目标函数的返回值。如下所示:

 1 /**
 2      * 功能:后置通知
 3      * 注解形式实现aop通知时,参数不能随便写,否则和目标函数对应不上,会报错
 4      * @param jp :切入点目标对象
 5      * @param returningvalue 返回值
 6      */
 7     @afterreturning(pointcut = "execution(public void com.hex.second.studentserviceimpl.addstudent(com.hex.second.student))",returning="returningvalue")
 8     public void myafterreturning(joinpoint jp,object returningvalue){
 9         system.out.println("我是注解方式的后置通知");
10         system.out.println("返回值是:"+returningvalue);
11     }

4. 异常通知

@afterthrowing(pointcut="execution(public void com.hex.second.studentserviceimpl.addstudent(com.hex.second.student))",throwing="e") 表示异常通知,其中trowing表示将抛出异常绑定到参数中。当切入函数抛出异常时将会触发,如下所示:

1 /**
2      * 异常通知
3      */
4     @afterthrowing(pointcut="execution(public void com.hex.second.studentserviceimpl.addstudent(com.hex.second.student))",throwing="e")
5     public void myafterthrow(joinpoint jp,throwable e){
6         system.out.println("我是注解方式的异常通知");
7     }

5. 环绕通知

@around(value="execution(public void com.hex.second.studentserviceimpl.addstudent(com.hex.second.student))") 环绕通知功能最全面,可以实现其他几种,其中参数使用proceedingjoinpoint,是joinpoint的子类。

 1 /**
 2      * 环绕通知
 3      * @param jp 才用的是joinpoint的子类
 4      */
 5     @around(value="execution(public void com.hex.second.studentserviceimpl.addstudent(com.hex.second.student))")
 6     public void myaround(proceedingjoinpoint jp){
 7         object obj = null;
 8         try {
 9 
10             // 前置通知
11             system.out.println("注解环绕实现前置通知。。。");
12             system.out.println("环绕通知:target="+jp.gettarget()+",method="+jp.getsignature().getname()+",args="+jp.getargs().length);
13             // 控制目标方法的执行 obj表示目标方法的返回值,表示执行addstudent(student)方法
14             //此方法控制目标方法的执行,如果不写此方法,则目标方法不会执行,此方法前的是前置通知,此方法后的是后置通知
15             obj = jp.proceed();
16             // 后置通知
17             system.out.println("注解环绕实现后置通知。。。");
18         } catch (throwable e) {
19             // 异常通知
20             system.out.println("注解环绕实现异常通知。。。");
21         }finally{
22             //最终通知
23             system.out.println("注解环绕实现最终通知。。。");
24         }
25     }

6. 最终通知

@after("execution(public void com.hex.second.studentserviceimpl.addstudent(com.hex.second.student))") 表示最终通知,不管是否抛出异常,都会得到执行,类似于finally。如下所示:

1 /**
2      * 最终通知,@after的参数为目标通知类的表达式
3      * joinpoint 用来获取目标函数的参数及对象等信息
4      */
5     @after("execution(public void com.hex.second.studentserviceimpl.addstudent(com.hex.second.student))")
6     public void myafter(joinpoint jp){
7         system.out.println("我是注解方式最终通知");
8         system.out.println("method="+jp.getsignature().getname()+",args数量="+jp.getargs().length+",target="+jp.gettarget());
9     }

7. 除了上述注解之外,还需要在sping容器中,配置对注解的支持和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:p="http://www.springframework.org/schema/p"
 5 xmlns:aop="http://www.springframework.org/schema/aop"
 6 xmlns:context="http://www.springframework.org/schema/context"
 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/aop
10  http://www.springframework.org/schema/aop/spring-aop.xsd
11  http://www.springframework.org/schema/context
12  http://www.springframework.org/schema/context/spring-context.xsd">
13      
14      <!-- 服务类 -->
15      <bean id="studentservice" class="com.hex.second.studentserviceimpl">
16          
17      </bean>
18      <!-- 将addstudent和通知进行关联 -->
19      <!-- 配置对注解方式aop的支持 -->
20      <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
21      <!-- 配置对注解的扫描 -->
22      <context:component-scan base-package="com.hex.second"></context:component-scan>
23 </beans>

通过schema方式实现aop

通过schema方式实现步骤如下:

1. 定义一个普通的类,分别实现各种功能的通知,参数和注解方式的一致。

如下所示:

 1 package com.hex.second;
 2 
 3 import org.aspectj.lang.joinpoint;
 4 import org.aspectj.lang.proceedingjoinpoint;
 5 
 6 /**
 7  * 通过schema配置的方式实现通知
 8  * @author administrator
 9  *
10  */
11 public class logaspectschema {
12     /**
13      * 前置通知,@before的参数为目标通知类的表达式
14      * joinpoint 用来获取目标函数的参数及对象等信息
15      */
16     public void mybefore(joinpoint jp){
17         system.out.println("我是schema方式的前置通知");
18         system.out.println("method="+jp.getsignature().getname()+",args数量="+jp.getargs().length+",target="+jp.gettarget());
19     }
20     
21     /**
22      * 功能:后置通知
23      * schema形式实现aop通知时,参数不能随便写,否则和目标函数对应不上,会报错
24      * @param jp :切入点目标对象
25      * @param returningvalue 返回值
26      */
27     public void myafterreturning(joinpoint jp,object returningvalue){
28         system.out.println("我是schema方式的后置通知");
29         system.out.println("返回值是:"+returningvalue);
30     }
31     
32     /**
33      * 异常通知
34      */
35     public void myafterthrow(joinpoint jp ,throwable ex){
36         system.out.println("我是schema方式的异常通知");
37         system.out.println("ex:"+ex.getmessage());
38     }
39     
40     /**
41      * 环绕通知
42      * @param jp 才用的是joinpoint的子类
43      */
44     public void myaround(proceedingjoinpoint jp){
45         object obj = null;
46         try {
47 
48             // 前置通知
49             system.out.println("schema环绕实现前置通知。。。");
50             system.out.println("schema环绕通知:target="+jp.gettarget()+",method="+jp.getthis()+",args="+jp.getargs().length);
51             // 控制目标方法的执行 obj表示目标方法的返回值,表示执行addstudent(student)方法
52             //此方法控制目标方法的执行,如果不写此方法,则目标方法不会执行,此方法前的是前置通知,此方法后的是后置通知
53             obj = jp.proceed();
54             // 后置通知
55             system.out.println("schema环绕实现后置通知。。。");
56         } catch (throwable e) {
57             // 异常通知
58             system.out.println("schema环绕实现异常通知。。。");
59         }finally{
60             //最终通知
61             system.out.println("schema环绕实现最终通知。。。");
62         }
63     }
64     
65     /**
66      * 最终通知
67      * @param jp
68      */
69     public void myafter(joinpoint jp){
70         system.out.println("我是schema方式的最终通知");
71     }
72 }

2. 在spring容器中配置

首先将通知类注入到spring ioc容器中,然后配置<aop:config>将业务类和切面类关联起来。如下所示:

 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:p="http://www.springframework.org/schema/p"
 5 xmlns:aop="http://www.springframework.org/schema/aop"
 6 xmlns:context="http://www.springframework.org/schema/context"
 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/aop
10  http://www.springframework.org/schema/aop/spring-aop.xsd
11  http://www.springframework.org/schema/context
12  http://www.springframework.org/schema/context/spring-context.xsd">
13      
14      <!-- 服务类 -->
15      <bean id="studentservice" class="com.hex.second.studentserviceimpl">
16          
17      </bean>
18      <bean id="logschema" class="com.hex.second.logaspectschema"></bean>
19      <aop:config>
20          <!-- 配置切入点 -->
21          <aop:pointcut expression="execution(public void com.hex.second.studentserviceimpl.deletestudent(int)) or execution(public void com.hex.second.studentserviceimpl.addstudent(com.hex.second.student))" id="pc"/>
22          <aop:aspect ref="logschema">
23              <!-- 通过schema实现的通知 -->
24              <aop:before method="mybefore" pointcut-ref="pc"/>
25              <aop:after-returning method="myafterreturning" pointcut-ref="pc" returning="returningvalue"/>
26              <aop:after-throwing method="myafterthrow" pointcut-ref="pc" throwing="ex" />
27              <aop:around method="myaround" pointcut-ref="pc"/>
28              <aop:after method="myafter"  pointcut-ref="pc"/>
29          </aop:aspect>
30      </aop:config>
31 </beans>

备注

假如你不够快乐
也不要把眉头深锁
人生本来短暂
为什么 还要栽培苦涩

打开尘封的门窗
让阳光雨露洒遍每个角落
走向生命的原野
让风儿熨平前额

博大可以稀释忧愁
深色能够覆盖浅色

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网