Spring AOP(面向切面编程)
一、AOP简介
1.AOP概念:Aspect Oriented Programming 面向切面编程
2.作用:本质上来说是一种简化代码的方式
继承机制
封装方法
动态代理
……
3.情景举例
①数学计算器接口[MathCalculator]
int add(int i,int j);
int sub(int i,int j);
int mul(int i, int j);
int div(int i,int j);
②提供简单实现[EasyImpl]
③在简单实现的基础上让每一个计算方法都能够打印日志[LoginImpl]
④缺陷
[1]手动添加日志繁琐,重复
[2]统一修改不便
[3]对目标方法本来要实现的核心功能有干扰,使程序代码很臃肿,不易于开发维护
⑤使用动态代理实现
[1]创建一个类,让这个类能够提供一个目标对象的代理对象
[2]在代理对象中打印日志
4.AOP术语!
AOP概述
●AOP(Aspect-Oriented Programming,面向切面编程):是一种新的方法论,是对传统 OOP(Object-Oriented Programming,面向对象编程)的补充。
●Spring的AOP既可以使用xml配置的方式实现,也可以使用注解的方式来实现!
4.1 横切关注点
从每个方法中抽取出来的同一类非核心业务。(抽离到方法中处理非核心业务)
4.2 切面(Aspect)
封装横切关注点信息的类,每个关注点体现为一个通知方法。
4.3 通知(Advice)
切面必须要完成的各个具体工作
4.4 目标(Target)
被通知的对象
4.5 代理(Proxy)
向目标对象应用通知之后创建的代理对象
4.6 连接点(Joinpoint)
横切关注点在程序代码中的具体体现,对应程序执行的某个特定位置。例如:类某个方法调用前、调用后、方法捕获到异常后等。
在应用程序中可以使用横纵两个坐标来定位一个具体的连接点:
4.7 切入点(pointcut):
定位连接点的方式。每个类的方法中都包含多个连接点,所以连接点是类中客观存在的事物。
如果把连接点看作数据库中的记录,那么切入点就是查询条件——AOP可以通过切入点定位到特定的连接点。
切点通过org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件。
5.在Spring中使用AOP实现日志功能
①Spring中可以使用注解或XML文件配置的方式实现AOP。
②导入jar包
com.springsource.net.sf.cglib -2.2.0.jar
com.springsource.org.aopalliance-1.0.0 .jar
com.springsource.org.aspectj.weaver-1.6.8 .RELEASE.jar
commons-logging-1.1.3. jar
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE. jar
③开启基于注解的AOP功能
< aop:aspectj-autoproxy />
④声明一个切面类,并把这个切面类加入到IOC容器中
@Aspect//表示这是一个切面类
@Component//加入IOC容器
public class LogAspect {}
⑤在切面类中声明通知方法
[1]前置通知:@Before
[2]返回通知:@AfterReturning
[3]异常通知:@AfterThrowing
[4]后置通知:@After
[5]环绕通知:@Around :环绕通知是前面四个通知的集合体!
@Aspect//表示这是一个切面类
@Component//将本类对象加入到IOC容器中!
public class LogAspect {
@Before(value="execution(public int com.neuedu.aop.target.MathCalculatorImpl.add(int, int))")
public void showBeginLog(){
System.out.println("AOP日志开始");
}
@After(value="execution(public int com.neuedu.aop.target.MathCalculatorImpl.add(int, int))")
public void showReturnLog(){
System.out.println("AOP方法返回");
}
@AfterThrowing(value="execution(public int com.neuedu.aop.target.MathCalculatorImpl.add(int, int))")
public void showExceptionLog(){
System.out.println("AOP方法异常");
}
@AfterReturning(value="execution(public int com.neuedu.aop.target.MathCalculatorImpl.add(int, int))")
public void showAfterLog(){
System.out.println("AOP方法结束");
}
}
⑥被代理的对象也需要加入IOC容器
@Component//加入IOC容器
public class MathCalculatorImpl {
public int add(int i,int j){
3 int result = i+j;
4 return result;
}
public int sub(int i,int j){
int result = i-j;
8 return result;
}
public int multi(int i,int j){
int result = i*j;
return result;
13 }
public int divide(int i,int j){
int result = i/j;
16 return result;
17 }
}
二、切入点表达式:
1.上述案例通过junit测试,会发现,我们调用目标类的四个方法只有add方法被加入了4个通知,
如果想所有的方法都加上这些通知,可以在切入点表达式处,将execution(public int com.neuedu.aop.target.MathCalculatorImpl.add(int, int)) 换成:
execution(public int com.neuedu.aop.target.MathCalculatorImpl.*(int, int))这样只要是有两个参数,且参数类型为int的方法在执行的时候都会执行其相应的通知方法!
2.①切入点表达式的语法格式
execution([权限修饰符] [返回值类型] [简单类名/全类名] [方法名]([参数列表]))
2.1 作用
通过表达式的方式定位一个或多个具体的连接点。
2.2 语法细节
①切入点表达式的语法格式
execution([权限修饰符] [返回值类型] [简单类名/全类名] [方法名]([参数列表])) |
②举例说明
表达式 |
execution(* com.atguigu.spring.ArithmeticCalculator.*(..)) |
含义 |
ArithmeticCalculator接口中声明的所有方法。 第一个“*”代表任意修饰符及任意返回值。 第二个“*”代表任意方法。 “..”匹配任意数量、任意类型的参数。 若目标类、接口与该切面类在同一个包中可以省略包名。 |
表达式 |
execution(public * ArithmeticCalculator.*(..)) |
含义 |
ArithmeticCalculator接口的所有公有方法 |
表达式 |
execution(public double ArithmeticCalculator.*(..)) |
含义 |
ArithmeticCalculator接口中返回double类型数值的方法 |
表达式 |
execution(public double ArithmeticCalculator.*(double, ..)) |
含义 |
第一个参数为double类型的方法。 “..” 匹配任意数量、任意类型的参数。 |
表达式 |
execution(public double ArithmeticCalculator.*(double, double)) |
含义 |
参数类型为double,double类型的方法 |
③在AspectJ中,切入点表达式可以通过 “&&”、“||”、“!”等操作符结合起来。
表达式 |
execution (* *.add(int,..)) || execution(* *.sub(int,..)) |
含义 |
任意类中第一个参数为int类型的add方法或sub方法 |
execution(* *.*(..))
1.任意参数,任意类型
2.任意返回值
3.用@PointCut注解统一声明,然后在其它通知中引用该统一声明即可!
需要注意的是:权限是不支持写通配符的,当然你可以写一个*表示所有权限所有返回值!
4.最详细的切入点表达式:
execution(public int com.neuedu.aop.target.MathCalculatorImpl.add(int, int))
5.最模糊的切入点表达式:
execution (* *.*(..))
6..统一声明切入点表达式
@Pointcut(value= "execution(public int com.atguigu.aop.target.EazyImpl.add(int,int))")
public void myPointCut(){}
3、通知方法的细节
①在通知中获取目标方法的方法名和参数列表
[1]在通知方法中声明一个JoinPoint类型的形参
[2]调用JoinPoint对象的getSignature()方法获取目标方法的签名
[3]调用JoinPoint对象的getArgs()方法获取目标方法的实际参数列表
②在返回通知中获取方法的返回值
[1]在@AfterReturning注解中添加returning属性
@AfterReturning (value="myPointCut()", returning= "result")
[2]在返回通知的通知方法中声明一个形参,形参名和returning属性的值一致
showReturnLog(JoinPoint joinPoint, Object result)
③在异常通知中获取异常对象
[1]在@ AfterThrowing注解中添加throwing属性
@AfterThrowing (value="myPointCut()",throwing= "throwable" )
[2]在异常通知的通知方法中声明一个形参,形参名和throwing属性值一致
showExceptinLog(JoinPoint joinPoint, Throwable throwable)
根据接口类型获取target对象时,实际上真正放在IOC容器中的对象是代理对象,而并不是目标对象本身!
4、.环绕通知:@Around
4.1.环绕通知需要在方法的参数中指定JoinPoint的子接口类型ProceedingJoinPoint为参数
@Around(value="pointCut()")
public void around(ProceedingJoinPoint joinPoint){
}
4.2.环绕通知会将其他4个通知能干的,自己都给干了!
注意:@Around修饰的方法一定要将方法的返回值返回!本身相当于代理!
@Around(value="pointCut()")
public Object around(ProceedingJoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
Signature signature = joinPoint.getSignature();
String methodName = signature.getName();
List<Object> list = Arrays.asList(args);
Object result = null;
try {
//目标方法之前要执行的操作
System.out.println("[环绕日志]"+methodName+"开始了,参数为:"+list);
//调用目标方法
result = joinPoint.proceed(args);
//目标方法正常执行之后的操作
System.out.println("[环绕日志]"+methodName+"返回了,返回值为:"+result);
} catch (Throwable e) { //目标方法抛出异常信息之后的操作
System.out.println("[环绕日志]"+methodName+"出异常了,异常对象为:"+e);
throw new RuntimeException(e.getMessage());
}finally{
//方法最终结束时执行的操作!
System.out.println("[环绕日志]"+methodName+"结束了!");
}
return result;
}
三、切面的优先级
对于同一个代理对象,可j以同时有多个切面共同对它进行代理。
可以在切面类上通过@Order (value=50)注解来进行设置,值越小优先级越高!
@Aspect
@Component
@Order(value=40)
public class TxAspect { @Around(value="execution(public * com.neuedu.aop.target.MathCalculatorImpl.*(..))")
public Object around(ProceedingJoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
Signature signature = joinPoint.getSignature();
String methodName = signature.getName();
List<Object> list = Arrays.asList(args);
Object result = null;
try {
//目标方法之前要执行的操作
System.out.println("[事务日志]"+methodName+"开始了,参数为:"+list);
//调用目标方法
result = joinPoint.proceed(args); //目标方法正常执行之后的操作
System.out.println("[事务日志]"+methodName+"返回了,返回值为:"+result);
} catch (Throwable e) {
//目标方法抛出异常信息之后的操作
System.out.println("[事务日志]"+methodName+"出异常了,异常对象为:"+e);
throw new RuntimeException(e.getMessage());
}finally{
//方法最终结束时执行的操作!
System.out.println("[事务日志]"+methodName+"结束了!");
}
return result;
} }
四、通过配置方式实现AOP
1、注意:上面的AOP都是通过注解实现的,AOP实际上也可以通过xml配置的方式实现!
①<!-- 1.将需要加载到IOC容器中的bean配置好 -->
<bean id="logAspect" class="com.neuedu.aop.proxy.LogAspect"></bean>
<bean id="txAspect" class="com.neuedu.aop.target.TxAspect"></bean>
<bean id="calculator" class="com.neuedu.aop.target.MathCalculatorImpl"></bean>
②<!-- 2.配置AOP,需要导入AOP名称空间 -->
<aop:config>
③<!-- 声明切入点表达式 -->
<aop:pointcut expression="execution(* com.neuedu.aop.target.MathCalculatorImpl.*(..))" id="myPointCut"/>
④<!-- 配置日志切面类,引用前面的类 ,通过order属性控制优先级-->
<aop:aspect ref="logAspect" order="25">
⑤<!-- 通过method属性指定切面类的切面方法,通过pointcut-ref指定切入点表达式 -->
<aop:before method="showBeginLog" pointcut-ref="myPointCut"/>
<aop:after method="showAfterLog" pointcut-ref="myPointCut"/>
<aop:after-throwing method="showExceptionLog" pointcut-ref="myPointCut" throwing="ex"/>
<aop:after-returning method="showReturnLog" pointcut-ref="myPointCut" returning="result"/>
<aop:around method="around" pointcut-ref="myPointCut"/>
</aop:aspect>
⑥<!-- 配置事务切面类,引用前面的类 -->
<aop:aspect ref="txAspect" order="20">
<aop:around method="around" pointcut-ref="myPointCut"/>
</aop:aspect>
</aop:config>
需要知道的是:事务的管理是和AOP是有很大关系的,即声明式事务的底层是用事务实现的!
Spring AOP(面向切面编程)的更多相关文章
- 详细解读 Spring AOP 面向切面编程(二)
本文是<详细解读 Spring AOP 面向切面编程(一)>的续集. 在上篇中,我们从写死代码,到使用代理:从编程式 Spring AOP 到声明式 Spring AOP.一切都朝着简单实 ...
- 浅谈Spring AOP 面向切面编程 最通俗易懂的画图理解AOP、AOP通知执行顺序~
简介 我们都知道,Spring 框架作为后端主流框架之一,最有特点的三部分就是IOC控制反转.依赖注入.以及AOP切面.当然AOP作为一个Spring 的重要组成模块,当然IOC是不依赖于Spring ...
- spring AOP面向切面编程学习笔记
一.面向切面编程简介: 在调用某些类的方法时,要在方法执行前或后进行预处理或后处理:预处理或后处理的操作被封装在另一个类中.如图中,UserService类在执行addUser()或updateUse ...
- 【Spring系列】Spring AOP面向切面编程
前言 接上一篇文章,在上午中使用了切面做防重复控制,本文着重介绍切面AOP. 在开发中,有一些功能行为是通用的,比如.日志管理.安全和事务,它们有一个共同点就是分布于应用中的多处,这种功能被称为横切关 ...
- 从源码入手,一文带你读懂Spring AOP面向切面编程
之前<零基础带你看Spring源码--IOC控制反转>详细讲了Spring容器的初始化和加载的原理,后面<你真的完全了解Java动态代理吗?看这篇就够了>介绍了下JDK的动态代 ...
- Spring AOP面向切面编程详解
前言 AOP即面向切面编程,是一种编程思想,OOP的延续.在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等等.在阅读本文前希望您已经对Spring有一定的了解 注:在能对代码进行添 ...
- Spring AOP 面向切面编程相关注解
Aspect Oriented Programming 面向切面编程 在Spring中使用这些面向切面相关的注解可以结合使用aspectJ,aspectJ是专门搞动态代理技术的,所以比较专业. ...
- Spring AOP 面向切面编程入门
什么是AOP AOP(Aspect Oriented Programming),即面向切面编程.众所周知,OOP(面向对象编程)通过的是继承.封装和多态等概念来建立一种对象层次结构,用于模拟公共行为的 ...
- 详细解读 Spring AOP 面向切面编程(一)
又是一个周末, 今天我要和大家分享的是 AOP(Aspect-Oriented Programming)这个东西,名字与 OOP 仅差一个字母,其实它是对 OOP 编程方式的一种补充,并非是取而代之. ...
- Spring Aop面向切面编程&&自动注入
1.面向切面编程 在程序原有纵向执行流程中,针对某一个或某一些方法添加通知,形成横切面的过程叫做面向切面编程 2.常用概念 原有功能:切点,pointcut 前置通知:在切点之前执行的功能,befor ...
随机推荐
- Bind("入库日期", "{0:yyyy-MM-dd}") 关于asp.net格式化数据库日期字符串
Bind("入库日期", "{0:yyyy-MM-dd}") 关于asp.net格式化数据库日期字符串,删除多余的000:0:00
- Mycat之日志分析 select * from travelrecord order by id limit 100000,100 的执行过程
解释:mycat在执行分页排序的时候,分成2步走.如果M很大,会改写成 limit 0,m+n, 然后在每个MYSQL分片上排序后还需要在mycat汇总输出,所以会很慢.下面是详细执行计划以及日志输出 ...
- SQL Where 字符串拼接
) set @s='1,2,3' --法一: --法二: exec('select * from tb where id in ('+@s+')')
- linux内核中task_struct与thread_info及stack三者的关系
在linux内核中进程以及线程(多线程也是通过一组轻量级进程实现的)都是通过task_struct结构体来描述的,我们称它为进程描述符.而thread_info则是一个与进程描述符相关的小数据结构,它 ...
- SpringMVC总结二:Controller的请求映射方式(RequestMapping)简单介绍
在SpringMVC总结一:快速入门的基础上简单介绍一下请求映射的方式: 1,标准映射规则 1. @RequestMapping可以设置在类上,也可以设置在方法上 2. 请求的映射规则是:类上的Req ...
- spring 项目返回406
406 The resource identified by this request is only capable of generating responses with characteris ...
- 7.python实现高效端口扫描器之nmap模块
对于端口扫描,使用的最多的就是nmap这个工具,不想python已经强大到,提供了nmap这个扫描端口的模块. 本片文章主要介绍nmap模块的两个常用类: PortScanner()类,实现一个nma ...
- OSG3.2+Qt5.2.1+VS2012+OSGEarth 2.5编译问题记录
问题1:CMake Error at D:/Qt/Qt5.2.1/5.2.1/msvc2012_64_opengl/lib/cmake/Qt5Gui/Qt5GuiConfigExtras.cmake: ...
- 在使用webstorm打开本地项目文件夹的html文件时,浏览器提示404错误
错误原因:在使用webstorm打开本地项目文件夹的html文件时,浏览器提示404错误. 错误分析:文件夹命名内包含“+”,此特殊符号导致浏览器解析错误. 改正方案:去掉特殊符号“+”
- (转)Asp.net页面生命周期详解任我行(1)-小试牛刀,编写页面代码
原文地址:http://www.cnblogs.com/xuyubing/archive/2013/10/01/3348344.html 前言 很久很久以前,还是我在学校的时候,我就看了传智里面视频, ...