一起学Spring之注解和Schema方式实现AOP
概述
在上一篇,我们了解了通过实现接口和XML配置的方式来实现AOP,在实现注解方式AOP之前,先了解一下AspectJ。AspectJ是一个面向切面的框架,它扩展了Java语言,定义了AOP语法,能够在编译时实现代码的注入。Spring通过集成ApsectJ实现了以注解方式定义通知类,大大减少了配置文件的工作量。本文主要讲解通过注解方式和Schema方式实现AOP编程,仅供学习分享使用,如有不足之处,还请指正。
实现AOP的三种方式:
- 通过实现相应接口,并配置Xml进行实现,可以参考上一篇。
- 通过注解方式实现。
- 通过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的更多相关文章
- Spring的xml文件配置方式实现AOP
配置文件与注解方式的有很大不同,多了很多配置项. beans2.xml <?xml version="1.0" encoding="UTF-8"?> ...
- Spring(十二)使用Spring的xml文件配置方式实现AOP
配置文件与注解方式的有非常大不同,多了非常多配置项. beans2.xml <?xml version="1.0" encoding="UTF-8"? & ...
- 2018-02-11 发布 spring 自定义注解(annotation)与 aop获取注解
知识点: Java自定义注解.spring aop @aspect的使用 首先我们先介绍Java自定义注解. 在开发过程中,我们实现接口的时候,会出现@Override,有时还会提示写@Suppres ...
- 【转】spring 自定义注解(annotation)与 aop获取注解
首先我们先介绍Java自定义注解. 在开发过程中,我们实现接口的时候,会出现@Override,有时还会提示写@SuppressWarnings.其实这个就是Java特有的特性,注解. 注解就是某种注 ...
- spring 代理注解 <aop:aspectj-autoproxy />
spring默认使用jdk的代理方式,使用jdk的代理方式我们知道,代理的类需要实现一个接口,若果没有就会报,java.lang.NoSuchMethodException: com.sun.prox ...
- Spring的注解方式实现AOP
Spring对AOP的实现提供了很好的支持.下面我们就使用Spring的注解来完成AOP做一个例子. 首先,为了使用Spring的AOP注解功能,必须导入如下几个包.aspectjrt.jar,asp ...
- 使用Spring的注解方式实现AOP
Spring对AOP的实现提供了很好的支持.下面我们就使用Spring的注解来完成AOP做一个例子. 首先,为了使用Spring的AOP注解功能,必须导入如下几个包.aspectjrt.jar,asp ...
- Spring注解和配置方式
Spring提供了一个org.springframework.beans.factory.FactoryBean工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑. 从Spring3.0开始, ...
- Spring 使用注解方式进行事务管理
转载:http://www.cnblogs.com/younggun/archive/2013/07/16/3193800.html 使用步骤: 步骤一.在spring配置文件中引入<tx:&g ...
随机推荐
- GitHub的高级搜索方式
平时在学完一个知识后,需要写些 demo来进行练手,这个时候 GitHub就是最好不过的资源库了,以下整理了一些关于在 github 上面找项目的一些小技巧. 一.单条件使用 项目名称 仓库名称包含 ...
- 快速入门函数式编程——以Javascript为例
函数式编程是在不改变状态和数据的情况下使用表达式和函数来编写程序的一种编程范式.通过遵守这种范式,我们能够编写更清晰易懂.更能抵御bug的代码.这是通过避免使用流控制语句(for.while.brea ...
- Java项目多版本部署及快速回滚(含完整命令)
1. 场景描述 java项目linux环境下快速部署,以前介绍过,今天主要结合linux的软连接,实现版本的快速切换(回滚),包含完整的start.sh与stop.sh,只需修改包名和路径即可运行,有 ...
- CentOS 7 ETCD集群配置大全
目录 前言 环境准备 安装 静态集群 配置 node01 配置文件 node02 配置文件 node03 配置文件 启动测试 查看集群状态 生成TLS证书 etcd证书创建 安装cfssl工具集 生成 ...
- js基础-函数-var和let的区别
javaScript简介 javaScript历史 1995年,Netscape公司是凭借Navigator浏览器成为当时第一代互联网公司. 网景公司希望在HTML界面上加一点动态效果,于是叫Bren ...
- Error creating bean with name 'entityManagerFactory' defined in class path resource解决方案
项目是集成了Spring Boot和Spring Data,然后昨天简单Jpa和Spring Boot配置完成,开始进行公司项目的重构,然后出现了这个问题.当时是在网上找了好久.后来发现时java ...
- Eclipse官方下载步骤
今天整理Eclipse项目时,发现自己的IDE不能用了,不兼容自己的JDK,于是决定去官网下载一个适合的IDE,由于官网全部都是英文,所以不是太容易找到,于是就想着出一篇博客帮助以后的人更好的更快的下 ...
- [ch04-05] 梯度下降的三种形式
系列博客,原文在笔者所维护的github上:https://aka.ms/beginnerAI, 点击star加星不要吝啬,星越多笔者越努力. 4.5 梯度下降的三种形式 我们比较一下目前我们用三种方 ...
- 挑战10个最难的Java面试题(附答案)【下】【华为云技术分享】
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...
- Eclipse for Tricore 的安装方法
1.安装JDK32位版 2.安装Eclipse for Tricore 32位版(应该也只有32位的) 3.OK(如果打开Tricore提示找不到JDK的话,在网上搜索如何配置JDK,修改环境变量) ...