概述

在上一篇,我们了解了通过实现接口和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注解,表名此类为切面通知类。

如下所示:

 package com.hex.second;

 import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component; /**
* @Aspect:声明类为一个通知类
* @Component("logAnnotation"):通过注解方法生成一个Bean,但是需要配置注解的支持
* 通过注解的方式声明通知
* @author Administrator
*
*/
@Component("logAnnotation")
@Aspect
public class LogAspectAnnotation { }

2. 前置通知函数

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

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

 /**
* 前置通知,@Before的参数为目标通知类的表达式
* JoinPoint 用来获取目标函数的参数及对象等信息
*/
@Before("execution(public void com.hex.second.StudentServiceImpl.addStudent(com.hex.second.Student))")
public void MyBefore(JoinPoint jp){
System.out.println("我是注解方式的前置通知");
System.out.println("method="+jp.getSignature().getName()+",args数量="+jp.getArgs().length+",target="+jp.getTarget());
}

3. 后置通知

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

 /**
* 功能:后置通知
* 注解形式实现AOP通知时,参数不能随便写,否则和目标函数对应不上,会报错
* @param jp :切入点目标对象
* @param returningValue 返回值
*/
@AfterReturning(pointcut = "execution(public void com.hex.second.StudentServiceImpl.addStudent(com.hex.second.Student))",returning="returningValue")
public void MyAfterReturning(JoinPoint jp,Object returningValue){
System.out.println("我是注解方式的后置通知");
System.out.println("返回值是:"+returningValue);
}

4. 异常通知

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

 /**
* 异常通知
*/
@AfterThrowing(pointcut="execution(public void com.hex.second.StudentServiceImpl.addStudent(com.hex.second.Student))",throwing="e")
public void MyAfterThrow(JoinPoint jp,Throwable e){
System.out.println("我是注解方式的异常通知");
}

5. 环绕通知

@Around(value="execution(public void com.hex.second.StudentServiceImpl.addStudent(com.hex.second.Student))") 环绕通知功能最全面,可以实现其他几种,其中参数使用ProceedingJoinPoint,是JoinPoint的子类。

 /**
* 环绕通知
* @param jp 才用的是JoinPoint的子类
*/
@Around(value="execution(public void com.hex.second.StudentServiceImpl.addStudent(com.hex.second.Student))")
public void MyAround(ProceedingJoinPoint jp){
Object obj = null;
try { // 前置通知
System.out.println("注解环绕实现前置通知。。。");
System.out.println("环绕通知:target="+jp.getTarget()+",method="+jp.getSignature().getName()+",args="+jp.getArgs().length);
// 控制目标方法的执行 obj表示目标方法的返回值,表示执行addStudent(student)方法
//此方法控制目标方法的执行,如果不写此方法,则目标方法不会执行,此方法前的是前置通知,此方法后的是后置通知
obj = jp.proceed();
// 后置通知
System.out.println("注解环绕实现后置通知。。。");
} catch (Throwable e) {
// 异常通知
System.out.println("注解环绕实现异常通知。。。");
}finally{
//最终通知
System.out.println("注解环绕实现最终通知。。。");
}
}

6. 最终通知

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

 /**
* 最终通知,@After的参数为目标通知类的表达式
* JoinPoint 用来获取目标函数的参数及对象等信息
*/
@After("execution(public void com.hex.second.StudentServiceImpl.addStudent(com.hex.second.Student))")
public void MyAfter(JoinPoint jp){
System.out.println("我是注解方式最终通知");
System.out.println("method="+jp.getSignature().getName()+",args数量="+jp.getArgs().length+",target="+jp.getTarget());
}

7. 除了上述注解之外,还需要在Sping容器中,配置对注解的支持和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:p="http://www.springframework.org/schema/p"
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"> <!-- 服务类 -->
<bean id="studentService" class="com.hex.second.StudentServiceImpl"> </bean>
<!-- 将addStudent和通知进行关联 -->
<!-- 配置对注解方式AOP的支持 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!-- 配置对注解的扫描 -->
<context:component-scan base-package="com.hex.second"></context:component-scan>
</beans>

通过Schema方式实现AOP

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

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

如下所示:

 package com.hex.second;

 import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint; /**
* 通过Schema配置的方式实现通知
* @author Administrator
*
*/
public class LogAspectSchema {
/**
* 前置通知,@Before的参数为目标通知类的表达式
* JoinPoint 用来获取目标函数的参数及对象等信息
*/
public void MyBefore(JoinPoint jp){
System.out.println("我是Schema方式的前置通知");
System.out.println("method="+jp.getSignature().getName()+",args数量="+jp.getArgs().length+",target="+jp.getTarget());
} /**
* 功能:后置通知
* Schema形式实现AOP通知时,参数不能随便写,否则和目标函数对应不上,会报错
* @param jp :切入点目标对象
* @param returningValue 返回值
*/
public void MyAfterReturning(JoinPoint jp,Object returningValue){
System.out.println("我是Schema方式的后置通知");
System.out.println("返回值是:"+returningValue);
} /**
* 异常通知
*/
public void MyAfterThrow(JoinPoint jp ,Throwable ex){
System.out.println("我是Schema方式的异常通知");
System.out.println("ex:"+ex.getMessage());
} /**
* 环绕通知
* @param jp 才用的是JoinPoint的子类
*/
public void MyAround(ProceedingJoinPoint jp){
Object obj = null;
try { // 前置通知
System.out.println("Schema环绕实现前置通知。。。");
System.out.println("Schema环绕通知:target="+jp.getTarget()+",method="+jp.getThis()+",args="+jp.getArgs().length);
// 控制目标方法的执行 obj表示目标方法的返回值,表示执行addStudent(student)方法
//此方法控制目标方法的执行,如果不写此方法,则目标方法不会执行,此方法前的是前置通知,此方法后的是后置通知
obj = jp.proceed();
// 后置通知
System.out.println("Schema环绕实现后置通知。。。");
} catch (Throwable e) {
// 异常通知
System.out.println("Schema环绕实现异常通知。。。");
}finally{
//最终通知
System.out.println("Schema环绕实现最终通知。。。");
}
} /**
* 最终通知
* @param jp
*/
public void MyAfter(JoinPoint jp){
System.out.println("我是Schema方式的最终通知");
}
}

2. 在Spring容器中配置

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

 <?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:p="http://www.springframework.org/schema/p"
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"> <!-- 服务类 -->
<bean id="studentService" class="com.hex.second.StudentServiceImpl"> </bean>
<bean id="logSchema" class="com.hex.second.LogAspectSchema"></bean>
<aop:config>
<!-- 配置切入点 -->
<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"/>
<aop:aspect ref="logSchema">
<!-- 通过Schema实现的通知 -->
<aop:before method="MyBefore" pointcut-ref="pc"/>
<aop:after-returning method="MyAfterReturning" pointcut-ref="pc" returning="returningValue"/>
<aop:after-throwing method="MyAfterThrow" pointcut-ref="pc" throwing="ex" />
<aop:around method="MyAround" pointcut-ref="pc"/>
<aop:after method="MyAfter" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
</beans>

备注

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

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

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

一起学Spring之注解和Schema方式实现AOP的更多相关文章

  1. Spring的xml文件配置方式实现AOP

    配置文件与注解方式的有很大不同,多了很多配置项. beans2.xml <?xml version="1.0" encoding="UTF-8"?> ...

  2. Spring(十二)使用Spring的xml文件配置方式实现AOP

    配置文件与注解方式的有非常大不同,多了非常多配置项. beans2.xml <?xml version="1.0" encoding="UTF-8"? & ...

  3. 2018-02-11 发布 spring 自定义注解(annotation)与 aop获取注解

    知识点: Java自定义注解.spring aop @aspect的使用 首先我们先介绍Java自定义注解. 在开发过程中,我们实现接口的时候,会出现@Override,有时还会提示写@Suppres ...

  4. 【转】spring 自定义注解(annotation)与 aop获取注解

    首先我们先介绍Java自定义注解. 在开发过程中,我们实现接口的时候,会出现@Override,有时还会提示写@SuppressWarnings.其实这个就是Java特有的特性,注解. 注解就是某种注 ...

  5. spring 代理注解 <aop:aspectj-autoproxy />

    spring默认使用jdk的代理方式,使用jdk的代理方式我们知道,代理的类需要实现一个接口,若果没有就会报,java.lang.NoSuchMethodException: com.sun.prox ...

  6. Spring的注解方式实现AOP

    Spring对AOP的实现提供了很好的支持.下面我们就使用Spring的注解来完成AOP做一个例子. 首先,为了使用Spring的AOP注解功能,必须导入如下几个包.aspectjrt.jar,asp ...

  7. 使用Spring的注解方式实现AOP

    Spring对AOP的实现提供了很好的支持.下面我们就使用Spring的注解来完成AOP做一个例子. 首先,为了使用Spring的AOP注解功能,必须导入如下几个包.aspectjrt.jar,asp ...

  8. Spring注解和配置方式

    Spring提供了一个org.springframework.beans.factory.FactoryBean工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑. 从Spring3.0开始, ...

  9. Spring 使用注解方式进行事务管理

    转载:http://www.cnblogs.com/younggun/archive/2013/07/16/3193800.html 使用步骤: 步骤一.在spring配置文件中引入<tx:&g ...

随机推荐

  1. 微信小程序使用 ECharts 实现数据可视化

    微信小程序使用 ECharts 显示图表 首先创建微信小程序 这里就不再赘述 下载 GitHub 上的 ecomfe/echarts-for-weixin 下载后解压,打开文件夹,里面的 ec-can ...

  2. 剑指Offer-27.字符串的排列(C++/Java)

    题目: 输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. 输入描述: 输入 ...

  3. Markdown学习笔记(一)

    解决Markdown文件插入图片无法只能本地查看的问题 原因:图片的显示与图片地址关联,写入Markdown时用的本机地址,一旦上传到网络,地址就发生了变化,也就显示不了图片. 寻找免费的图床网站. ...

  4. 【2018寒假集训 Day2】【动态规划】维修栅栏

    维修栅栏 问题描述: 小z最近当上了农场主!不过,还没有来得及庆祝,一件棘手的问题就摆在了小z的面前.农场的栅栏,由于年久失修,出现了多处破损.栅栏是由n块木板组成的,每块木板可能已经损坏也可能没有损 ...

  5. 国内开源C# WPF控件库Panuon.UI.Silver推荐

    国内优秀的WPF开源控件库,Panuon.UI的优化版本.一个漂亮的.使用样式与附加属性的WPF UI控件库,值得向大家推荐使用与学习. 今天站长(Dotnet9,站长网址:https://dotne ...

  6. 前端vue实现pdf文件的在线预览

    3.前端vue实现pdf文件的在线预览 我是通过 <iframe> 标签就可以满足我工作的 pdf预览需求 如果<iframe> 无法满足需求 , 可以使用pdf.js这个插件 ...

  7. 【Android - 问题解决】之Android Studio在Refreshing Gradle Project卡住的问题

    今天把Android Studio从2.2版本升级到了2.3版本,但是再打开以前项目的时候,就卡在 “Refreshing XXX Gradle Project” 这里不动了. 网上搜了一些解决方案, ...

  8. Docker 自建私有Registry 私有仓库

    目录 说明 介绍 原理 搭建 查看配置文件 启动 上传和下载镜像测试 测试上传镜像 测试下载镜像 说明 记录搭建 docker 私有仓库步骤 介绍 docker镜像可以托管到dockerhub中,跟代 ...

  9. luogu P1566 加等式

    题目描述 对于一个整数集合,我们定义"加等式"如下:集合中的某一个元素可以表示成集合内其他元素之和.如集合{1,2,3}中就有一个加等式:3=1+2,而且3=1+2 和3=2+1是 ...

  10. JQuery中操作元素的属性_对象属性

    我们主要是通过attr去获取元素的属性: 看body内容: <body> <p> 账号:<input type="text" id="una ...