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

前端之家收集整理的这篇文章主要介绍了一起学Spring之注解和Schema方式实现AOP前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

概述

上一篇,我们了解了通过实现接口和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  org.aspectj.lang.ProceedingJoinPoint;
 5  org.aspectj.lang.annotation.AfterReturning;
 6  org.aspectj.lang.annotation.AfterThrowing;
 7  org.aspectj.lang.annotation.Around;
 8  org.aspectj.lang.annotation.Aspect;
 9  org.aspectj.lang.annotation.Before;
10  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 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表示定义目标函数的返回值。如下所示:

 2      * 功能:后置通知
     * 注解形式实现AOP通知时,参数不能随便写,否则和目标函数对应不上,会报错
     * @param jp :切入点目标对象
 returningValue 返回值
 6       7     @AfterReturning(pointcut = "execution(public void com.hex.second.StudentServiceImpl.addStudent(com.hex.second.Student))",returning="returningValue" 8      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表示将抛出异常绑定到参数中。当切入函数抛出异常时将会触发,如下所示:

     * 异常通知
3      4     @AfterThrowing(pointcut="execution(public void com.hex.second.StudentServiceImpl.addStudent(com.hex.second.Student))",throwing="e"5      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的子类。

     * 环绕通知
 jp 才用的是JoinPoint的子类
 4       5     @Around(value="execution(public void com.hex.second.StudentServiceImpl.addStudent(com.hex.second.Student))" 6      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。如下所示:

     * 最终通知,@After的参数为目标通知类的表达式
     * JoinPoint 用来获取目标函数的参数及对象等信息
4      5     @After("execution(public void com.hex.second.StudentServiceImpl.addStudent(com.hex.second.Student))"6      MyAfter(JoinPoint jp){
7         System.out.println("我是注解方式最终通知"8         System.out.println("method="+jp.getSignature().getName()+",1)">9     }

7. 除了上述注解之外,还需要在Sping容器中,配置对注解的支持和AOP的自动扫描。

如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<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
 http://www.springframework.org/schema/beans/spring-beans.xsd
 http://www.springframework.org/schema/aop
 http://www.springframework.org/schema/aop/spring-aop.xsd
11  http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context.xsd">
13      
14      <!-- 服务类 -->
15      bean id="studentService" class="com.hex.second.StudentServiceImpl"16          
17      </bean18       将addStudent和通知进行关联 19       配置对注解方式AOP的支持 20      aop:aspectj-autoproxy></21       配置对注解的扫描 22      context:component-scan base-package="com.hex.second"context:component-scan23 beans>

通过Schema方式实现AOP

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

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

如下所示:

 5 
 * 通过Schema配置的方式实现通知
10   LogAspectSchema {
12          * 前置通知,@Before的参数为目标通知类的表达式
16     17         System.out.println("我是Schema方式的前置通知"18         System.out.println("method="+jp.getSignature().getName()+",1)">19     }
20     
21     22      * Schema形式实现AOP通知时,参数不能随便写,否则和目标函数对应不上,会报错
25 26      27     28         System.out.println("我是Schema方式的后置通知"29         System.out.println("返回值是:"+30 31     
32     33 34      35     36         System.out.println("我是Schema方式的异常通知"37         System.out.println("ex:"+ex.getMessage());
38 39     
40     41 42 43      44     45         Object obj = 46         47 
48             49             System.out.println("Schema环绕实现前置通知。。。"50             System.out.println("Schema环绕通知:target="+jp.getTarget()+",method="+jp.getThis()+",1)">51             52             53             obj =54             55             System.out.println("Schema环绕实现后置通知。。。"56         } 57             58             System.out.println("Schema环绕实现异常通知。。。"59         }60             61             System.out.println("Schema环绕实现最终通知。。。"62 63 64     
65     66      * 最终通知
67  jp
68      69     70         System.out.println("我是Schema方式的最终通知"71 72 }
View Code

2. 在Spring容器中配置

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

="logSchema"="com.hex.second.LogAspectSchema"aop:config20           配置切入点 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-ref25              aop:after-returning ="MyAfterReturning"="pc" returning="returningValue"26              aop:after-throwing ="MyAfterThrow" throwing="ex" 27              aop:around ="MyAround"28              aop:after ="MyAfter"  pointcut-ref29          aop:aspect30      31 >
View Code

备注

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

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

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

原文链接:https://www.f2er.com/spring/882596.html

猜你在找的Spring相关文章