基于注解的Sping AOP详解
一、创建基础业务
package com.kang.sping.aop.service; import org.springframework.stereotype.Service; //使用注解@Service声明bean
@Service
public class UserService { public void add(){
System.out.println("此时调用add()方法....");
} public String delete(){
System.out.println("此时调用delete()方法....");
return "delete的原返回值";
} public void edit(){
System.out.println("此时调用edit()方法 ....");
int i = 5/0;
}
}
二、配置Sping的XML文件
applicationContext.xml
<?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: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-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 自动扫描的包 -->
<context:component-scan base-package="com.kang.sping.aop"></context:component-scan> <!-- 使 AspectJ 的注解起作用 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
三、创建增强处理类
package com.kang.sping.aop.entities; import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/*
* @Component注解声明bean
* @Aspect注解声明这是一个切面
* 在同一个连接点上应用不止一个切面时, 除非明确指定, 否则它们的优先级是不确定的.
* 切面的优先级可以利用 @Order 注解指定.值越小, 优先级越高。
*/ @Component
@Aspect
//@Order(0) 设置优先级
public class Operator {
/*
* @Pointcut将一个切入点声明成简单的方法. 切入点的方法体通常是空的, 因为将切入点定义与应用程序逻辑混在一起是不合理的。
* 切入点方法的访问控制符同时也控制着这个切入点的可见性. 如果切入点要在多个切面中共用, 最好将它们集中在一个公共的类中.
* 在这种情况下, 它们必须被声明为 public. 在引入这个切入点时, 必须将类名也包括在内.
* 如果类没有与这个切面放在同一个包中, 还必须包含包名.
*
* Spring AOP支持的切入点指示符,execution用来匹配执行方法的连接点
* 1、@Pointcut("execution(* com.kang.sping.aop.service..*.*(..))")
* 第一个*表示匹配任意的方法返回值,..(两个点)表示零个或多个。上面的第一个..表示service包及其子包,
* 第二个*表示所有类,第三个*表示所有方法,第二个..表示方法的任意参数个数。
* 2、@Pointcut("within(com.kang.sping.aop.service.*)")
* within限定匹配方法的连接点,上面的就是表示匹配service包下的任意连接点
* 3、@Pointcut("this(com.kang.sping.aop.service.UserService)")
* this用来限定AOP代理必须是指定类型的实例,如上,指定了一个特定的实例,就是UserService
* 4、@Pointcut("bean(userService)") bean也是非常常用的,bean可以指定IOC容器中的bean的名称
*/
@Pointcut("execution(* com.kang.sping.aop.service..*.*(..))")
public void pointCut() {//声明切入点方法为pointCut()
} /*
* @Before 表示在目标方法执行之前执行,@Before 里面的是切入点表达式或切入点函数 可以在通知方法中声明一个类型为 JoinPoint
* 的参数. 然后就能访问链接细节,如方法名称和参数值.
* 获取方法名:joinPoint.getSignature().getName()
* 获取参数列表:joinPoint.getArgs();
*/
@Before("pointCut()")
public void doBefore(JoinPoint joinPoint) {
// joinPoint.getSignature().getName();
// joinPoint.getArgs();
System.out.println("Before通知方法...");
} @After("pointCut()")
public void doAfter(JoinPoint joinPoint) {
System.out.println("After通知方法...");
} /*
* @AfterReturning(pointcut = "pointCut()", returning = "returnVal")
* returning:指定一个返回值形参名,代表了目标方法的返回值, 增强处理定义的方法可以通过该参数访问目标方法的返回值。
* 因此必须在通知方法的签名中添加一个同名参数.afterReturn(JoinPoint joinPoint, Object returnVal)
* 在运行时, Spring AOP 会通过这个参数传递返回值. 与@After的区别:
* After增强处理无论目标方法如何结束(执行成功或者异常终止),都会执行.
* AfterReturning增强处理只有在目标方法执行成功后才会运行。
*/
@AfterReturning(pointcut = "pointCut()", returning = "returnVal")
public void afterReturn(JoinPoint joinPoint, Object returnVal) {
System.out.println("AfterReturning通知方法获得的代理方法返回值是:"+returnVal);
System.out.println("AfterReturning通知方法...");
} /*
* @AfterThrowing 只在连接点抛出异常时才执行异常通知。将 throwing 属性添加到 @AfterThrowing 注解中,
* 也可以访问连接点抛出的异常。 Throwable 是所有错误和异常类的超类. 所以在异常通知方法可以捕获到任何错误和异常.
* 如果只对某种特殊的异常类型感兴趣, 可以将参数声明为其他异常的参数类型. 然后通知就只在抛出这个类型及其子类的异常时才被执行.
*/
@AfterThrowing(pointcut = "pointCut()", throwing = "error")
public void afterThrowing(JoinPoint joinPoint, Throwable error) {
System.out.println("AfterThrowing通知方法捕获的异常是:"+error);
System.out.println("AfterThrowing通知方法...");
} /*
* @Around 对于环绕通知来说, 连接点的参数类型必须是 ProceedingJoinPoint . 它是 JoinPoint 的子接口,
* 允许控制何时执行, 是否执行连接点。在环绕通知中需要明确调用 ProceedingJoinPoint 的 proceed()
* 方法来执行被代理的方法,可以传入一个Object[]对象,该数组中的值将被传入目标方法作为执行方法的实参。 如果没有调用proceed()就会导致通知被执行了, 但目标方法没有被执行。 注意:
* 环绕通知的方法需要返回目标方法执行之后的结果, 即调用 joinPoint.proceed(); 的返回值, 否则会出现空指针异常
* 事实上,在Around通知方法中可以修改原方法的返回值。而AfterReturning得到的返回值也是由Around决定的。
*/
@Around("pointCut()")
public Object around(ProceedingJoinPoint pjp) { try {
System.out.println("Around通知方法,在原方法执行前...");
Object obj=pjp.proceed();
obj="Around通知方法方法的返回值";
System.out.println("Around通知方法,在原方法执行后...");
System.out.println("Around通知方法的返回值是:"+obj);
return obj;
} catch (Throwable e) {
e.printStackTrace();
}
return null; } }
四、编写测试方法
1、测试没有返回值的方法(add)
package com.kang.sping.aop.main; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import com.kang.sping.aop.service.UserService; public class Test {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserService userService = (UserService) ctx.getBean("userService");
userService.add();
}
}
测试结果
分析以上结果可以得出以下结论 :
(1)通知执行的优先级
进入目标方法时,先织入Around,再织入Before,退出目标方法时,先织入Around,再织入AfterReturning,最后才织入After。
注意:Spring AOP的环绕通知会影响到AfterThrowing通知的运行,不要同时使用!同时使用也没啥意义。
(2)Around可以改变原方法的返回值,而AfterReturning得到的返回值实际上是Around通知方法的返回值。
2、测试有返回值的方法(delete)
package com.kang.sping.aop.main; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import com.kang.sping.aop.service.UserService; public class Test {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserService userService = (UserService) ctx.getBean("userService"); Object obj=userService.delete();
System.out.println("delete方法的最终返回值是:"+obj);
}
}
测试结果:
可以看到,Around的返回值影响了AfterReturning得到的返回值和原方法执行后的最终返回值。
3、测试出现异常的方法(edit)(这里将@Around通知方法注释掉,否则会影响AfterThrowing的运行)
package com.kang.sping.aop.main; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import com.kang.sping.aop.service.UserService; public class Test {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserService userService = (UserService) ctx.getBean("userService"); userService.edit();
}
}
测试结果:
可以看到AfterThrowing方法的执行在After方法之后。
五、总结
Around增强处理可以获得目标方法的最大控制权,既可以完全控制目标方法的执行,也可以改变执行目标方法的参数,还可以改变目标方法的返回值。任何通知(Advice)方法可以将第一个参数定义为 org.aspectj.lang.JoinPoint 类型。JoinPoint 接口提供了一系列有用的方法, 比如 getArgs() (返回方法参数)、getThis() (返回代理对象)、getTarget() (返回目标)、getSignature()
(返回正在被通知的方法相关信息)和 toString() (打印出正在被通知的方法的有用信息。)
基于注解的Sping AOP详解的更多相关文章
- 基于XML配置的Sping AOP详解
一.编写基本处理方法 package com.kang.sping.xml.aop; public class Math{ //加 public int add(int n1,int n2){ int ...
- Spring4 AOP详解
Spring4 AOP详解 第一章Spring 快速入门并没有对Spring4 的 AOP 做太多的描述,是因为AOP切面编程概念不好理解.所以这章主要从三个方面详解AOP:AOP简介(了解),基于注 ...
- 【转载】Spring AOP详解 、 JDK动态代理、CGLib动态代理
Spring AOP详解 . JDK动态代理.CGLib动态代理 原文地址:https://www.cnblogs.com/kukudelaomao/p/5897893.html AOP是Aspec ...
- [Spring学习笔记 5 ] Spring AOP 详解1
知识点回顾:一.IOC容器---DI依赖注入:setter注入(属性注入)/构造子注入/字段注入(注解 )/接口注入 out Spring IOC容器的使用: A.完全使用XML文件来配置容器所要管理 ...
- Spring AOP详解及简单应用
Spring AOP详解 一.前言 在以前的项目中,很少去关注spring aop的具体实现与理论,只是简单了解了一下什么是aop具体怎么用,看到了一篇博文写得还不错,就转载来学习一下,博文地址: ...
- 转:Spring AOP详解
转:Spring AOP详解 一.前言 在以前的项目中,很少去关注spring aop的具体实现与理论,只是简单了解了一下什么是aop具体怎么用,看到了一篇博文写得还不错,就转载来学习一下,博文地址: ...
- Android注解支持Support Annotations详解
###注解支持(Support Annotations)Android support library从19.1版本开始引入了一个新的注解库,它包含很多有用的元注解,你能用它们修饰你的代码,帮助你发现 ...
- Spring全家桶——SpringBoot之AOP详解
Spring全家桶--SpringBoot之AOP详解 面向方面编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象编程(OOP). OOP中模块化的关键单元是类,而在AOP中,模块化单元是方 ...
- Spring Aop 详解二
这是Spring Aop的第二篇,案例代码很详解,可以查看https://gitee.com/haimama/java-study/tree/master/spring-aop-demo. 阅读前,建 ...
随机推荐
- 【Codevs1993】草地排水(最大流,Dinic)
题意:在农夫约翰的农场上,每逢下雨,Bessie最喜欢的三叶草地就积聚了一潭水.这意味着草地被水淹没了,并且小草要继续生长还要花相当长一段时间.因此,农夫约翰修建了一套排水系统来使贝茜的草地免除被大水 ...
- java并发之hashmap源码
在上篇博客中分析了hashmap的用法,详情查看java并发之hashmap 本篇博客重点分析下hashmap的源码(基于JDK1.8) 一.成员变量 HashMap有以下主要的成员变量 /** * ...
- Codeforces Round #321 (Div. 2) Kefa and Dishes 状压+spfa
原题链接:http://codeforces.com/contest/580/problem/D 题意: 给你一些一个有向图,求不超过m步的情况下,能获得的最大权值和是多少,点不能重复走. 题解: 令 ...
- Java中Javadoc的{@link}与@see的简单区别
{@link}与@see这两个Javadoc注解都可以直接链接类和方法.用法基本一致. 但是@see必须顶头写,而{@link可以任意地方},如下所示: 参考: http://blog.csdn.ne ...
- Spring Cloud ZooKeeper集成Feign的坑3,程序Run模式运行没事,Debug模式下报错
请更新Spring Cloud的版本: <dependency> <groupId>org.springframework.cloud</groupId> < ...
- weblogic运维时经常遇到的问题和常用的配置
希望这篇能把weblogic运维时经常遇到的问题.常用的配置汇总到一起. 1.配置jvm参数: 一般在domain启动过程中会看到以下启动的日志信息,如下图所示: 图中红色方框部分为启动weblo ...
- Frotinet60D IP映射 開放指定端口是實際應用
有多個外網IP的環境中,在某一部電腦上,如何使用多個外網IP中的某一個?且為使用的Bitcomet開放TCP,TUP特定端口? 1.在本機windows防火墻中"輸入" 和&quo ...
- python(3)- 循环语句:从最内层跳出多层循环
跳出多层循环:三层循环,最里层直接跳出3层 方法一: 在Python中,函数运行到return这一句就会停止,因此可以利用这一特性,将功能写成函数,终止多重循环 def work(): #定义函数 f ...
- eclipse从svn检出项目
在eclipse的project explorer 右键->import->svn->从svn检出项目,然后填写资源库的位置,完成,然后一直next. 直到项目检出完成后,选择项目, ...
- C# HTTP请求后对gzip页面实现解压缩
1.通过socket页面请求后的receive内容不能经过string后再进行解压缩处理 会造成错误的gzip幻数报错 推荐使用流处理 2.正确分析返回内容 分割header和页面代码部分 3.对页面 ...