Spring 梳理-AOP
- 界面应用场景
- 日志、声明式事务、安全、缓存
- AOP功能演化图
- 图片引用地址:https://www.cnblogs.com/best/p/5679656.html
- AOP设计模式-代理模式
- 静态代理:手动编写代理类,手动编写代码拦截每个方法。工作量极大。
- JDK代理:利用反射,实现InvocationHandler接口。 业务类需要实现“业务接口”,利用反射技术代理该“业务接口”
- 动态代理:利用cglib。cglib是一种动态代码生成器,可以在运行期动态生成代理类
- AOP术语
- 关注点:重复代码就叫做关注点;
- 切面: 关注点形成的类,就叫切面(类)!是通知和节点的集合,这个集合决定了切面:是什么,在何时和何处完成其功能。
- 通知(advice):切面类函数。切面要完成的工作(切面类中的方法)。通知定义了切面是什么以及何时使用。Spring的通知有5种类型:before、after、after-returning、after-throwing和around这五种类型。
- 连接点(joinpoint):程序事件。连接点表示在何种操作发生时应用切面。比如方法调用时、修改字段时和抛出异常时等。我们的应用可能有数以千计的时机,这些时机被称为连接点。连接点是应用执行过程中能够插入切面的一个点。
- 切点(拦截的作用)(pointcut): 执行目标对象方法,动态植入切面代码。可以通过切入点表达式,指定拦截哪些类的哪些方法; 给指定的类在运行的时候植入切面类代码。切点有助于缩小切面所通知的连接点的范围。如果说通知定义了切面“是什么”、“何时”,那么切点就定义了“何处”。
- 可能应用有很多事件(连接点)可以用来对外提供“触角”,但通过某种方式选定的连接点与通知发生作用,这个连接点成为切点。
- Spring AOP构建在动态代理基础之上,因此,Spring对AOP的支持局限于方法拦截
- Spring 项目与AspectJ项目 之间有大量的合作;Spring 使用 AspectJ项目的注解语法,实现Spring自己基于代理的AOP。也就是Spring与AspectJ在注解的语法上是相同的,但底层实现是不同的,Spring底层只支持方法拦截,无法在bean创建时应用通知将;,AspectJ却支持构造器、属性、方法拦截。
- Spring AOP的切面类的编写使用纯java语法;
- AspectJ AOP的切面类编写使用java语言扩展,自成一套新的语法。
- Spring在运行时才创建AOP代理对象。
- 联合使用@Component@Aspect,将切面类以一个普通的全局单实例bean的形式注入到容器中,;可以在其他业务类型的bean中使用@Autowired注解 将切面类bean注入到普通业务bean中,获取其运行时状态值。
- Spring使用AsjpectJ定义切点表达式
- 明确具体方法 execution( * cn.jt.ClassA.run(..))
- 限定切点所属的包 execution(* cn.jt.ClassA.run(..)) within(cn.*)
- 限定切点所在bean execution(* cn.jt.ClassA.run(..)) and bean(‘beanID’)
- 使用AOP,为已封装好的Java类,添加新的方法,实现类似Ruby的动态类的概念。但实际上,Spring将一个bean分拆到多个类中:原有类方法在一个类中,新添加的方法在一个类中。
- XML方式实现AOP编程 :在没有源码,或者不想把AspectJ注解污染到代码之中的情况下使用
- 步骤
1) 引入jar文件 【aop 相关jar, 4个】
2) 引入aop名称空间
3)aop 配置
* 配置切面类 (重复执行代码形成的类)
* 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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- dao 实例 在这里配置后就不用在类中使用注解 -->
<bean id="aDao" class="xx"></bean>
<bean id="bDao" class="yy"></bean> <!-- 切面类 -->
<bean id="aop" class="aopClass1"></bean> <!-- Aop配置 -->
<aop:config>
<!-- 定义一个切入点表达式: 拦截哪些方法 -->
<aop:pointcut expression="execution(* aopClass1.*.*(..))" id="pt"/>
<!-- 切面 -->
<aop:aspect ref="aop">
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pt"/>
<!-- 前置通知: 在目标方法调用前执行 -->
<aop:before method="begin" pointcut-ref="pt"/>
<!-- 后置通知: -->
<aop:after method="after" pointcut-ref="pt"/>
<!-- 返回后通知 -->
<aop:after-returning method="afterReturning" pointcut-ref="pt"/>
<!-- 异常通知 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pt"/> </aop:aspect>
</aop:config>
</beans>
-
- 步骤
- 注解方式实现AOP编程
- 先引入aop相关jar文件
spring-aop-3.2.5.RELEASE.jar
aopalliance.jar
aspectjweaver.jar
aspectjrt.jar
bean.xml中引入aop名称空间
开启aop注解
- 使用注解
-
@Aspect 指定一个类为切面类
@Pointcut("execution(* cn.itcast.e_aop_anno.*.*(..))") 指定切入点表达式
@Before("pointCut_()") 前置通知: 目标方法之前执行
@After("pointCut_()") 后置通知:目标方法之后执行(始终执行)
@AfterReturning("pointCut_()") 返回后通知: 执行方法结束前执行(异常不执行)
@AfterThrowing("pointCut_()") 异常通知: 出现异常时候执行
@Around("pointCut_()") 环绕通知: 环绕目标方法执行
-
- 关于@Pointcut注解
- 是一个节点表达式,通过在一个空函数run()上使用@Pointcut注解,我们实际上扩展了切点表达式语言,这样就可以在任何切点表达式中使用run(),否则,需要在每个切点表达式使用那个更长的表达式。例如:
@AspectJ
public class Audience{
@Pointcut("execution(** cn.jt.run(..))")
public void run(){} @Before("run()")
public void beforeRun(ProceedingJoinPoint jp){
System.out.println("berfor");
jp.proceed();
System.out.println("after");
} @Around("run()")
public void watchRun(ProceedingJoinPoint jp){
System.out.println("berfor");
jp.proceed();
System.out.println("after");
} }相当于:
@AspectJ
public class Audience{
@Before("execution(** cn.jt.run(..))")
public void beforeRun(){
System.out.println("berfor");
} @Around("execution(** cn.jt.run(..))")
public void watchRun(ProceedingJoinPoint jp){
System.out.println("berfor");
jp.proceed();
System.out.println("after");
} }
- 关于环绕通知:
- 环绕通知需要额外的ProceedingJoinPoint类型参数
- 如果不调用jp.proceed()方法,那么通知会阻塞对被通知方法的调用;或者调用多次,类似与“失败后重试”这样的业务逻辑。
- 将业务类方法中的参数,传递到通知(切面类方法)中。(使用 args 表达式)
@Component
@Aspect
public class Audience { private Map<Integer, Integer> trackCounts = new HashMap<>(); @Pointcut("execution(** concert.JayPerform.playTrack(int)) && args(trackNum)") //<1>
public void track(int trackNum) {} //<2> @AfterReturning("track(trackNum)") //<3>
public void countTrack(int trackNum) //<4>
{ int currentCount = getPlayCount(trackNum);
trackCounts.put(trackNum, currentCount+);
System.out.println("------- 这首歌播放了"+(currentCount+)+"次");
} public int getPlayCount(int trackNumber)
{
return trackCounts.containsKey(trackNumber)?trackCounts.get(trackNumber):;
}
}- 代码中 <1>、<2>、<3>、<4> 处,int型参数的名称都是trackNum,这样保证了从命名切点到通知方法的参数转移。并且,这里的参数trackNum与concert.JayPerform.playTrack(int trackNum) 的参数命名相同。
经过实验,发现这4处的参数名称与concert.JayPerform.playTrack(int trackNum)中的参数名称不必相同,只要<1>与<2>处参数名称相同、<3>与<4>处参数名称相同即可
- 示例
- bean.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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 使用注解时要开启注解扫描 要扫描的包 -->
<context:component-scan base-package="cn.jt"></context:component-scan> <!-- 开启aop注解方式 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
-
- Java代码
@Component //加入IOC容器
@Aspect // 指定当前类为切面类
public class Aop { // 指定切入点表达式: 拦截哪些方法; 即为哪些类生成代理对象
//解释@Pointcut("execution(* cn.jt.*.*(..))")
//@Pointcut("execution(* 切入点表达式固定写法, cn.itcast.e_aop_anno表示包.类名(可以用*表示包下所有的类).方法名(可以用*表示类下所有的方法)(..)表示参数可以用..
@Pointcut("execution(* cn.jt.*.*(..))")
public void pointCut_(){
} //@Before("execution(* cn.jt.*.*(..))")每个方法需要写相同的引用,所以将相同的部分抽取到一个空的方法中pointCut_(),
// 前置通知 : 在执行目标方法之前执行
@Before("pointCut_()")
public void begin(){
System.out.println("开始事务/异常");
} // 后置/最终通知:在执行目标方法之后执行 【无论是否出现异常最终都会执行】
@After("pointCut_()")
public void after(){
System.out.println("提交事务/关闭");
} // 返回后通知: 在调用目标方法结束后执行 【出现异常不执行】
@AfterReturning("pointCut_()")
public void afterReturning() {
System.out.println("afterReturning()");
} // 异常通知: 当目标方法执行异常时候执行此关注点代码
@AfterThrowing("pointCut_()")
public void afterThrowing(){
System.out.println("afterThrowing()");
} // 环绕通知:环绕目标方式执行
@Around("pointCut_()")
public void around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("环绕前....");
pjp.proceed(); // 执行目标方法
System.out.println("环绕后....");
} }测试类
public class App { ApplicationContext ac =
new ClassPathXmlApplicationContext("cn/jt/bean.xml"); // 目标对象有实现接口,spring会自动选择“JDK代理”
@Test
public void testApp() {
IUserDao userDao = (IUserDao) ac.getBean("userDao");
System.out.println(userDao.getClass());
userDao.save();
} // 目标对象没有实现接口, spring会用“cglib代理”
@Test
public void testCglib() {
OrderDao orderDao = (OrderDao) ac.getBean("orderDao");
System.out.println(orderDao.getClass());
orderDao.save();
}
- bean.xml
- 先引入aop相关jar文件
Spring 梳理-AOP的更多相关文章
- Spring 梳理 - AOP那些学术概念—通知、增强处理连接点(JoinPoint)切面(Aspect)
Spring AOP那些学术概念—通知.增强处理连接点(JoinPoint)切面(Aspect) 1.我所知道的AOP 初看起来,上来就是一大堆的术语,而且还有个拉风的名字,面向切面编程,都说是 ...
- Spring系列.AOP原理简析
Spring AOP使用简介 Spring的两大核心功能是IOC和AOP.当我们使用Spring的AOP功能时是很方便的.只需要进行下面的配置即可. @Component @Aspect public ...
- Spring基于AOP的事务管理
Spring基于AOP的事务管理 事务 事务是一系列动作,这一系列动作综合在一起组成一个完整的工作单元,如果有任何一个动作执行失败,那么事务 ...
- Spring实现AOP的4种方式
了解AOP的相关术语:1.通知(Advice):通知定义了切面是什么以及何时使用.描述了切面要完成的工作和何时需要执行这个工作.2.连接点(Joinpoint):程序能够应用通知的一个“时机”,这些“ ...
- spring的AOP
最近公司项目中需要添加一个日志记录功能,就是可以清楚的看到谁在什么时间做了什么事情,因为项目已经运行很长时间,这个最初没有开来进来,所以就用spring的面向切面编程来实现这个功能.在做的时候对spr ...
- Spring(五)AOP简述
一.AOP简述 AOP全称是:aspect-oriented programming,它是面向切面编号的思想核心, AOP和OOP既面向对象的编程语言,不相冲突,它们是两个相辅相成的设计模式型 AOP ...
- Spring中AOP原理,源码学习笔记
一.AOP(面向切面编程):通过预编译和运行期动态代理的方式在不改变代码的情况下给程序动态的添加一些功能.利用AOP可以对应用程序的各个部分进行隔离,在Spring中AOP主要用来分离业务逻辑和系统级 ...
- Spring之AOP面向切片
一.理论基础: AOP(Aspectoriented programming)面向切片/服务的编程,在Spring中使用最多的是对事物的处理.而AOP这种思想在程序中很多地方可以使用的,比如说, ...
- 利用CGLib实现动态代理实现Spring的AOP
当我们用Proxy 实现Spring的AOP的时候, 我们的代理类必须实现了委托类的接口才能实现. 而如果代理类没有实现委托类的接口怎么办? 那么我们就可以通过CGLib来实现 package cn. ...
随机推荐
- 2019icpc南京网络赛_F_Greedy Sequence
题意 题意不明,队友告诉我对于每个\(i\),所在下标\(p[i]\),在\([p[i]-k,p[i]+k]\)中找到小于\(i\)的最大数\(x\),然后\(ans[i]=ans[x]+1\)即可. ...
- 云原生生态周报 Vol. 17 | Helm 3 发布首个 beta 版本
本周作者 | 墨封.衷源.元毅.有济.心水 业界要闻 1. Helm 3 首个 beta 版本 v3.0.0-beta.1 发布 该版本的重点是完成最后的修改和重构,以及移植其他 Helm 2 特性. ...
- mac入门之设置
mac入门: 一般手机软件,都是分设置和业务功能:操作系统亦是如此,设置+必备应用:用设置入门十分合理. 总览: 通用:通用,顾明思意是设置的设置,设置是独立应用之外或者公共的开关,通用更抽象一层,没 ...
- winform和WPF的那点事~
一.定义 1.Winform的定义: WinForm是·Net开发平台中对Windows Form的一种称谓. 2.WPF的定义: WPF(Windows Presentation Foundatio ...
- 微擎 人人商城 对接京东vop 对接京东商品,同步商品 地址,库存,价格,上下架等。(二) 设置后台管理界面
昨天提到了,由于vop商品池未开通,故对接工作只能暂缓,现在要做一个专门针对vop商品的后台管理, 老规矩,先上设计链路图 因为后台本来就是有比较完善的商品管理系统, 所以我们只是针对vop 进行简单 ...
- 《快照读、当前读和MVCC》
1.快照读 快照读是基于 MVCC 和 undo log 来实现的,适用于简单 select 语句,避免了幻读. 读已提交:一个事务内操作一条数据,可以查询到另一个已提交事务操作同一条数据的最新值.( ...
- 图论之拓扑排序 poj 2367 Genealogical tree
题目链接 http://poj.org/problem?id=2367 题意就是给定一系列关系,按这些关系拓扑排序. #include<cstdio> #include<cstrin ...
- Codefroces 939 C Convenient For Everybody
939 C 题意:若干年以后地球会变成n个时区, 为了方便计时, 每个时区的时间从1:00开始到n:00点结束, 现在将要举行一场c赛, 每个时区内都有ai个人参加,并且比赛开始时间不早于当地时间s: ...
- lightoj 1245 Harmonic Number (II)(简单数论)
题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1245 题意:求f(n)=n/1+n/2.....n/n,其中n/i保留整数 显 ...
- spark与mapreduce的区别
spark是通过借鉴Hadoop mapreduce发展而来,继承了其分布式并行计算的优点,并改进了mapreduce明显的缺陷,具体表现在以下几方面: 1.spark把中间计算结果存放在内存中,减少 ...