AOP思想和重要术语: 数据源:javaBean
OOP(面向对象编程)
AOP(横切面编程):
同时存在A/B/C三个类,三个类同时存在权限检查、日志检查、开始事物、提交回滚操作,还有具体的业务,只有具体不同,其他都相同 我们可以把每一个功能叫做切面,面向切面的编程,
就是面上切面的角度思考。每一个切面是以一个功能模块存在的(类)
之前: A类 B类 C类
权限检查 权限检查 权限检查(切面)
日志检查 日志检查 日志检查(切面)
开始事物 开始事物 开始事物(切面)
具体业务 具体业务 具体业务 (不相同)
提交、回滚 提交、回滚 开始、事物(切面)
面向切面编程之后:
A类、B类、C类 三个类谁需要哪项操作 就直接把哪项操作插入进来就可以了,从这里看出 动态代理就AOP的原理。
公共相同的操作
A类 B类 C类
权限检查————————————>
日志检查————————————>
开始事物————————————>
具体业务 具体业务 具体业务 (不相同)
开始、事物——————————>
面向切面的术语:
1.连接点(JoinPoint):需要被增强的方法
例如:一个类中有多个方法,这多个方法都需要被增强,每一个方法就叫做连接点。(WHERE) 去哪里做增强操作——————--——————> 地点
2.切入点(PointCut):就是需要为哪些包中的方法做增强,JoinPoint的集合(WHERE) 去哪些地方做增强操作————————————> 地点------->貌似小时候造句
3.增强(Advice):当拦截到JoinPoint之后,在方法执行的某一个时机(WHEN)------------------------------------————————————> 时间
做怎么样的增强操作 (WHAT)------------------------------------————————————> 做什么
形象的例子:
Aspect(切面): 代表一个功能类---增强方法所用到的功能类,一个切面就是一个功能类(例如,记监测日志,就有一个监测日志的类)
在一个包里面有很多类这些类里面的方法需要被增强
切入点(PointCut)就是这个包里面的某个类的某个方法 (单个)
连接点(JoinPoint)就是这个包里面的所有类的所有的方法 (集合)
方法执行的时机:
1.前置增强:
2.后置增强:
3.异常增强:
4.最终增强:
5.环绕增强:
public class ABCD(){ 方法执行时机: public void dowork(){
|----- public void A(){} · JoinPoint try{
PointCut| public void B(){} |____·JoinPoint <----------------------前置增强
|----- public void C(){} |____·JoinPoint 业务代码
} <----------------------后置增强
}catch(Exception e){
异常处理
<----------------------异常增强
}finally{
释放资源
<---------------------最终增强
}
} 环绕增强 是前四个的合体,稍后会讲
4.切面(Pointcut+Advice):
去哪些地方+在什么时机+做什么增强
(地点) (时间) (干什么)
5.Target(目标对象):被代理的目标你对象。
6.Weaving(织入):把Advice加到Target上,被创建出代理对象的过程。 __________。_____。____。______。_______。就想织毛衣,把增强的的步骤串联起来
这一步是Spring帮我们完成的。
7.一个类被AOP织入之增强之后,创建出来的代理对象。
PointCut的语法:
JoinPoint、PointCut 在编程过程中 你怎么知道到哪个包以及哪个类下面的哪个方法去进行增强操作。不能写死,不能所有的方法都要做增强。
AOP联盟:提出AOP的规范,而不是sun公司。
提示怎么表示切入点(pointcut的问题)
AspectJ(面向切面的编程的框架,java语言),AspectC(C语言)
excution( <修饰符>? <返回类型> <声明类型>? <方法名> (<参数>) <异常>? )
| | | | | |
| | | | | |
Class类中的forName方法的全限定名称: | | | | | |
| | | | | |
V V V V V V
举例: public static Class java.lang.Class. forName (String className) Throws ClassNoFoundException
通配符
*:表示匹配任何部分,只能表示一个单词,多个单词的话不能用*表示。
..:用于全限定名中和方法参数中,分别表示子包和0到N个参数。出现的位置: <参数><...>表示多个参数,<方法名><...>表示该包和该包里面的子包
常见写法:
看表达式应该在后面往前看
execution(public * * (..))
public 方法的修饰符
* 表示:任意返回类型
* 表示:任意方法名称
(..) 表示:0到N个参数
整体表达:对public修饰的 任意返回类型 任意方法名 任意个参数的方法进做增强。
execution(* set *(..))
(..) 表示:0到N个参数
set * 表示:setXX的方法名称
* 表示:任意返回类型
整体表达:对任意返回类型 方法名为setXX的方法 任意个参数的方法进做增强。
execution(* com.xyz.service.AccountService.*(..))
(..) 表示:0到N个参数
com.xyz.service.AccountService.*:表示在com.xyz.service.AccountService.下面的所有方法
* 表示:任意返回类型
整体表达:对任意返回类型 在com.xyz.service.AccountService.* AccountService类下面的所有方法 任意个参数的方法进做增强。
execution(* com.xyz.service.*.*(..))
整体表达:对任意返回类型 在com.xyz.service.*.* 下面的所有类的所有方法 任意个参数的方法进做增强。
针对自己的项目写一个表达式:对Spring_StaticPoxy_Service包下面的所有类的所有的方法做增强
execution(* Spring_StaticPoxy_Service.*.*(..))
XML的配置
功能 <bean id="tx"/>
<!--1.配置AOP 需要配置 WHAT 做什么 --> 配置AOP <aop:config>
<!-- 处理事务 What--> 切面--具体的功能 <aop:aspect ref="tx">
<bean id="transcations" class="Transcations.Source_Transcation"/> AOP的作用域范围: <aop:pointcut id="tx_Arare" expression="execution(* Spring_StaticPoxy_Service.*Service.*(..))"/>
<aop:config proxy-target-class="true"> 对某一个方法的具体方法: <aop:before method="" pointcut-ref="tx_Arare"/>
<!-- 2.增强的具体操作 关联我们的 WHAT--><!--具体的增强操作 -->
<aop:aspect ref="transcations" >
<!-- 3.做增强的范围 WHERE--><!-- 配置AOP 在哪些包中的哪些类中的哪些方法做增强 -->
<aop:pointcut id="TX_Area" expression="execution(* Spring_StaticPoxy_Service.*Service.*(..))"/><!--JoinPoint点的集合——>
<!-- 4.什么时间做增强 关联我们的WHEN --><!-- 配置AOP 在方法的执行的什么时机做增强 -->
<aop:before method="openSource" pointcut-ref="TX_Area"/>
<aop:after-returning method="CommitSource" pointcut-ref="TX_Area"/>
<aop:after-throwing method="RollbackSource" pointcut-ref="TX_Area"/>
</aop:aspect>
</aop:config>
<!-- <aop:aspectj-autoproxy proxy-target-class="true"/> spring aop代理混用的问题- JDK 动态代理和CGLIB字节码增强技术代理的混用 -->
AOP的各种增强:
方法执行时机: public void dowork(){
public void A(){} · JoinPoint try{
public void B(){} |____·JoinPoint <----------------------前置增强
public void C(){} |____·JoinPoint 业务代码
} <----------------------后置增强
}catch(Exception e){
异常处理
<----------------------异常增强
}finally{
释放资源
<---------------------最终增强
}
} 环绕增强 是前四个的合体,稍后会讲
具体增强的功能 <bean id="tx"/>
配置AOP <aop:config>
切面--具体的功能 <aop:aspect ref="tx">
AOP的作用域范围: <aop:pointcut id="tx_Arare" expression="execution(* Spring_StaticPoxy_Service.*Service.*(..))"/>(被增强方法的集合)
对某一个方法的具体方法: <aop:before method="" pointcut-ref="tx_Arare"/>
根据在连接点方法(JoinPoint,需要被增强的方法)中执行时机的不同,我们把增强划分为五种情况。
前置增强(before):被增强方法之前执行。 权限控制,日志记录等等。
后置增强(after-returning):被增强的方法执行完毕之后执行(中途无异常)。 提交事物,统计数据的结果。
异常增强(after-throwing):被增强的方法出现异常的时候执行。 回滚事务,记录日志异常信息
最终增强(after):被增强的方法无论是否有异常,最终都要执行的增强操作(finally) 释放资源
环绕增强(around):非常强大,可以自定义在被增强方法的什么时候执行(返回一个Object) 前四种的合体。
AOP的细节:
1. 异常增强(after-throwing)获取异常信息:
<aop:after-throwing method="RollbackSource" pointcut-ref="TX_Area" throwing="excption"/> 在XML配置文件中的异常增强中有一个参数throwing="excption",
设置完参数之后,也要在对应的增强类中的方法,加上相同的参数名称的一个Throwable类型的参数。
//增强事务方法
public void RollbackSource(Throwable excption) {
System.out.println("--------回滚事物---------"+excption.getMessage());
}
//运行之后:显示如下
--------开启事物---------
--------回滚事物---------故意出错!--回滚事物
--------关闭事物---------
2.获取被增强方法的所有信息:
Spring AOP 中有一个JoinPoint类--连接点--被增强的方法:
被增强的方法的真实对象:
被增强的方法的代理对象:
被增强的方法的方法参数:
。。。。。。。。
可以作为前置、后置、异常、最终、环绕的参数,第一个参数。
以开启事务 为例子:
public void openSource(JoinPoint joinpoint) {
System.out.println("--------代理对象---------"+joinpoint.getThis().getClass());
System.out.println("--------真实目标对象---------"+joinpoint.getTarget().getClass());
System.out.println("--------被增强方法的参数---------"+Arrays.toString(joinpoint.getArgs()));
System.out.println("---------连接点的签名--------"+joinpoint.getSignature());
System.out.println("--------当前连接点的类型---------"+joinpoint.getKind());
System.out.println("--------开启事物---------");
}
其他的增强方法都可以加,注意:JoinPoint joinpoint要作为第一个参数
3.环绕增强:怎么玩呢?
//首先配置XML
<!-- 使用环绕增强 -->
<aop:around method="AroundMethod" pointcut-ref="TX_Area"/>
//环绕增强的方法
public Object AroundMethod(ProceedingJoinPoint jp) {
Object obj="环绕增强";
System.out.println("-------开启事务----------");
try {
System.out.println("-------记录日志----------");
obj=jp.proceed();//调用真实对象的方法
System.out.println("-------提交事务----------");
} catch (Throwable e) {
System.out.println("------回滚事务-----------");
}finally {
System.out.println("-------释放资源----------");
}
return obj;
}
源码百度云盘自取: 链接:https://pan.baidu.com/s/1GH5BCwF4VYms9NXDHIp00w 密码:hhsc