Spring中的AOP(二)
2.5 Spring的织入
在上一篇文章中,我们介绍了Pointcut、Advice、Advisor三个必要模块,剩下的工作就是把它们拼装起来,也就是织入过程。在Spring中,使用类org.springframework.aop.framework.ProxyFactory作为织入器。
2.5.1 认识ProxyFactory
首先,ProxyFactory并非Spring AOP中唯一可用的织入器,而是最基本的一个织入器实现。所以,我们就从这个最基本的织入器开始,了解一下织入过程到底是什么样子的。
使用ProxyFactory进行织入的逻辑很简单,只要为它提供生产代理对象的原材料,它就会返回那个织入完成的代理对象。我们来看示例代码:
ProxyFactory weaver = new ProxyFactory(yourTargetObject);
Advisor advisor = ...;
weaver.addAdvisor(advisor);
Object proxyObject = weaver.getProxy();
我们知道,Spring AOP在使用代理模式实现AOP的过程中采用了动态代理和CGLIB两种机制,分别对某些接口的目标类和没有实现任何接口的目标类进行代理,所以在使用ProxyFactory对目标类进行代理的时候,会通过ProxyFactory的某些行为控制属性对这两种情况进行区分。我们来看具体的场景,首先我们有一个接口,以及它的一个实现类:
public interface ITask {
void execute(TaskExecutionContext ctx);
}
public class MockTask implements ITask {
public void execute(TaskExecutionContext ctx) {
System.out.println("task execute.");
}
}
另外,我们还需要一个织入到Jointpoint的一个横切逻辑,也就是Advice实现。假设是PerformanceMethodInterceptor:
// 简单的检测系统某些方法的执行性能
public class PerformanceMethodInterceptor implements MethodInterceptor {
private final Log logger = LogFactory.getLog(this.getClass());
public Object invoke(MethodInvocation invocation) throws Throwable {
StopWatch watch = new StopWatch();
try {
watch.start();
return invocation.proceed();
} catch (Exception e) {
//TODO: handle exception
} finally {
watch.stop();
if (logger.isInfoEnabled()) {
logger.info(watch.toString());
}
}
}
}
- 基于接口的代理:
MockTask实现了ITask接口,要对这种实现了某些接口的目标类进行代理,我们使用setInterfaces(new Class[]{ITask.class})来明确告知ProxyFactory我们要对ITask接口类型进行代理。
ProxyFactory weaver = new ProxyFactory(new MockTask);
weaver.setInterfaces(new Class[]{ITask.class});
- 基于类的代理:如果目标类没有实现任何接口,
ProxyFactory会对目标类型进行基于类的代理,即使用CGLIB。假设我们现在有一个对象,定义如下:
public class Executable {
public void execute() {
System.out.println("Executable without any Interfaces");
}
}
织入的过程如下所示:
ProxyFactory weaver = new ProxyFactory(new Executable());
weaver.addAdvisor(advisor);
Executable proxyObject = (Executable)weaver.getProxy();
proxyObject.execute();
但是,即使目标对象类实现了至少一个接口,我们也可以通过proxyTargetClass属性强制ProxyFactory采用基于类的代理。除此之外,如果将ProxyFactory的optimize属性设为true的话,也会采用基于类的代理机制。
2.5.2 看清ProxyFactory的本质
我们不仅要知晓怎么使用ProxyFactory,并且还需要了解它其中的内部实现,这可以帮我们更好地使用它。我们先从它的根说起:
public interface AopProxy {
Object getProxy();
Object getProxy(ClassLoader classLoader)
}
这个接口对Spring AOP框架内的不同代理实现机制做了适度的抽象,目前,Spring提供了基于JDK动态代理和CGLIB两种机制的AopProxy实现。

首先,我们来看工厂类AopProxyFactory的定义:
public interface AopProxyFactory {
AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;
}
AopProxyFactory的实现类就一个,DefaultAopProxyFactory,它会根据传入的AdvisedSupport示例提供的相关信息,来决定生成什么类型的AopProxy,实现逻辑很简单,伪代码如下:
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
// 创建Cglib2AopProxy实例,并返回
} else {
// 创建JdkDynamicAopProxy实例,并返回
}
可以发现,生成的AopProxy类型是由AdvisedSupport实例来决定的,我们来看一下这个类到底是何方神圣。

AdvisedSupport继承了ProxyConfig类并实现了Advised接口。我们先来看ProxyConfig类,它其实就是个普通的JavaBean,它定义了5个boolean类型的属性,分别为proxyTargetClass(指定是否使用CGLIB代理)、optimize(告知代理对象是否要进行进一步优化,若为true,则使用CGLIB,默认为false)、opaque(控制代理对象是否可以强制转为Advised类型)、exposeProxy、frozen。
要生成代理对象,光有ProxyConfig提供的控制信息还不够,我们还需要生成代理对象的一些具体信息,比如Jointpoint和Advice,这些信息可以通过实现Advised接口来设置或者查询(addAdvisor()/removeAdvisor())。
那么,AopProxy、AdvisedSupport与ProxyFactory是什么关系呢?

ProxyFactory集AopProxy和AdvisedSupport于一身,所以可以通过它设置生成对象所需要的相关信息,也可以通过它取得最终生成的代理对象。前者是AdvisedSupport的职责,后者是AopProxy的职责。
至此,我们已经了解了ProxyFactory这个最基本的织入器实现,它还有几个兄弟,比如AspectJProxyFactory和ProxyFactoryBean,它们的关系如下所示,在此不作进一步说明,有兴趣的读者可以查阅《Spring揭秘》P179。

参考资料:《Spring揭秘》王福强
Spring中的AOP(二)的更多相关文章
- spring中的AOP 以及各种通知 配置
理解了前面动态代理对象的原理之后,其实还是有很多不足之处,因为如果在项目中有20多个类,每个类有100多个方法都需要判断是不是要开事务,那么方法调用那里会相当麻烦. spring中的AOP很好地解决了 ...
- Spring学习笔记(四)—— Spring中的AOP
一.AOP概述 AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.O ...
- 2018.12.24 Spring中的aop演示(也就是运用aop技术实现代理模式)
Aop的最大意义是:在不改变原来代码的前提下,也不对源代码做任何协议接口要求.而实现了类似插件的方式,来修改源代码,给源代码插入新的执行代码. 1.spring中的aop演示 aop:面向方面编程.不 ...
- (五)Spring 中的 aop
目录 文章目录 AOP概念 AOP原理 AOP术语 **`Spring`** 中的 **`aop`** 的操作 使用 `AspectJ` 实现 `aop` 的两种方式 AOP概念 浅理解 aop :面 ...
- Spring中的AOP
什么是AOP? (以下内容来自百度百科) 面向切面编程(也叫面向方面编程):Aspect Oriented Programming(AOP),通过预编译方式和运行期动态代理实现程序功能的统一维护的一种 ...
- Spring中关于AOP的实践之概念
一.什么是AOP AOP:也称作面向切面编程 在分享几个概念执行我想先举个栗子(可能例子举得并不是特别恰当): 1.假如路人A走在大街上,被一群坏人绑架了: 2.警察叔叔接到报警迅速展开行动:收集情报 ...
- Spring中的AOP 专题
Caused by: java.lang.IllegalArgumentException: ProceedingJoinPoint is only supported for around advi ...
- JavaWeb_(Spring框架)认识Spring中的aop
1.aop思想介绍(面向切面编程):将纵向重复代码,横向抽取解决,简称:横切 2.Spring中的aop:无需我们自己写动态代理的代码,spring可以将容器中管理对象生成动态代理对象,前提是我们对他 ...
- Spring 中基于 AOP 的 @AspectJ
Spring 中基于 AOP 的 @AspectJ @AspectJ 作为通过 Java 5 注释注释的普通的 Java 类,它指的是声明 aspects 的一种风格. 通过在你的基于架构的 XML ...
- Spring 中基于 AOP 的 XML架构
Spring 中基于 AOP 的 XML架构 为了使用 aop 命名空间标签,你需要导入 spring-aop j架构,如下所述: <?xml version="1.0" e ...
随机推荐
- 是时候扔掉cmder, 换上Windows Terminal
作为一个Windows的长期用户,一直没有给款好用的终端,知道遇到了 cmder,它拯救一个习惯用Windows敲shell命令的人. 不用跟我安利macOS真香!公司上班一直用macOS,一方面确实 ...
- Rocket - tilelink - TLArbiter
https://mp.weixin.qq.com/s/0ob-Fq-ZOoj-_S7pTJu6rQ 介绍TLArbiter的实现,主要关注如何实现burst的多个beat的输出. 1 ...
- 高性能可扩展mysql 笔记(三)Hash分区、RANGE分区、LIST分区
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 一.MySQL分区表操作 1.定义:数据库表分区是数据库基本设计规范之一,分区表在物理上表现为多个文件, ...
- 数据库之 MySQL --- 数据处理 之 子查询 (二)
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 一 .数据库语言定义及命令行查看数据库操作 -- SQL 语言可以分为三类-- DML: 数据操纵语言. ...
- Java实现 蓝桥杯 算法提高VIP 摆花 dp 记忆搜索 2种做法 多重背包
题目描述 小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆.通过调查顾客的喜好,小明列出了顾客最喜欢的n种花,从1到n标号.为了在门口展出更多种花,规定第i种花不能超过ai盆,摆花时 ...
- (Java实现) 洛谷 P1223 排队接水
题目描述 有n个人在一个水龙头前排队接水,假如每个人接水的时间为Ti,请编程找出这n个人排队的一种顺序,使得n个人的平均等待时间最小. 输入输出格式 输入格式: 输入文件共两行,第一行为n:第二行分别 ...
- Java 第十一届 蓝桥杯 省模拟赛 反倍数
反倍数 题目 问题描述 给定三个整数 a, b, c,如果一个整数既不是 a 的整数倍也不是 b 的整数倍还不是 c 的整数倍,则这个数称为反倍数. 请问在 1 至 n 中有多少个反倍数. 输入格式 ...
- Java实现 蓝桥杯算法提高金明的预算方案
题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:"你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过NN元 ...
- Java实现 蓝桥杯VIP 算法训练 Hankson的趣味题
问题描述 Hanks 博士是BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫Hankson.现 在,刚刚放学回家的Hankson 正在思考一个有趣的问题. 今天在课堂上,老师讲解了如 ...
- Java实现 LeetCode 215. 数组中的第K个最大元素
215. 数组中的第K个最大元素 在未排序的数组中找到第 k 个最大的元素.请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素. 示例 1: 输入: [3,2,1,5,6 ...