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采用基于类的代理。除此之外,如果将ProxyFactoryoptimize属性设为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类型)、exposeProxyfrozen

要生成代理对象,光有ProxyConfig提供的控制信息还不够,我们还需要生成代理对象的一些具体信息,比如Jointpoint和Advice,这些信息可以通过实现Advised接口来设置或者查询(addAdvisor()/removeAdvisor())。

那么,AopProxyAdvisedSupportProxyFactory是什么关系呢?

ProxyFactoryAopProxyAdvisedSupport于一身,所以可以通过它设置生成对象所需要的相关信息,也可以通过它取得最终生成的代理对象。前者是AdvisedSupport的职责,后者是AopProxy的职责。

至此,我们已经了解了ProxyFactory这个最基本的织入器实现,它还有几个兄弟,比如AspectJProxyFactoryProxyFactoryBean,它们的关系如下所示,在此不作进一步说明,有兴趣的读者可以查阅《Spring揭秘》P179。

参考资料:《Spring揭秘》王福强

Spring中的AOP(二)的更多相关文章

  1. spring中的AOP 以及各种通知 配置

    理解了前面动态代理对象的原理之后,其实还是有很多不足之处,因为如果在项目中有20多个类,每个类有100多个方法都需要判断是不是要开事务,那么方法调用那里会相当麻烦. spring中的AOP很好地解决了 ...

  2. Spring学习笔记(四)—— Spring中的AOP

    一.AOP概述 AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.O ...

  3. 2018.12.24 Spring中的aop演示(也就是运用aop技术实现代理模式)

    Aop的最大意义是:在不改变原来代码的前提下,也不对源代码做任何协议接口要求.而实现了类似插件的方式,来修改源代码,给源代码插入新的执行代码. 1.spring中的aop演示 aop:面向方面编程.不 ...

  4. (五)Spring 中的 aop

    目录 文章目录 AOP概念 AOP原理 AOP术语 **`Spring`** 中的 **`aop`** 的操作 使用 `AspectJ` 实现 `aop` 的两种方式 AOP概念 浅理解 aop :面 ...

  5. Spring中的AOP

    什么是AOP? (以下内容来自百度百科) 面向切面编程(也叫面向方面编程):Aspect Oriented Programming(AOP),通过预编译方式和运行期动态代理实现程序功能的统一维护的一种 ...

  6. Spring中关于AOP的实践之概念

    一.什么是AOP AOP:也称作面向切面编程 在分享几个概念执行我想先举个栗子(可能例子举得并不是特别恰当): 1.假如路人A走在大街上,被一群坏人绑架了: 2.警察叔叔接到报警迅速展开行动:收集情报 ...

  7. Spring中的AOP 专题

    Caused by: java.lang.IllegalArgumentException: ProceedingJoinPoint is only supported for around advi ...

  8. JavaWeb_(Spring框架)认识Spring中的aop

    1.aop思想介绍(面向切面编程):将纵向重复代码,横向抽取解决,简称:横切 2.Spring中的aop:无需我们自己写动态代理的代码,spring可以将容器中管理对象生成动态代理对象,前提是我们对他 ...

  9. Spring 中基于 AOP 的 @AspectJ

    Spring 中基于 AOP 的 @AspectJ @AspectJ 作为通过 Java 5 注释注释的普通的 Java 类,它指的是声明 aspects 的一种风格. 通过在你的基于架构的 XML ...

  10. Spring 中基于 AOP 的 XML架构

    Spring 中基于 AOP 的 XML架构 为了使用 aop 命名空间标签,你需要导入 spring-aop j架构,如下所述: <?xml version="1.0" e ...

随机推荐

  1. 个人工具,编辑器visual studio code

    个人收集的使用方法:简化版 主要基于基础web前端开发,visual studio code教程——基础使用.扩展插件安装使用 下载地址: https://visualstudio.microsoft ...

  2. 本地安装JDK1.7和1.8,可相互快速切换

    1.JDK官网下载jdk1.7和jdk1.8 https://www.oracle.com/java/technologies/javase-jdk8-downloads.html 2.将jdk1.7 ...

  3. 工业级CC1125模块有哪些优势?主要应用领域?

    CC1125无线模块是基于 TI 的 CC1125无线收发芯片设计,是一款完整的.体积小巧的.低功耗的无线收发模块.是 TI Chipcon 推出的 ISM 频段高性能无线收发芯片之一,最大输出功率可 ...

  4. Java实现 蓝桥杯VIP 算法训练 黑白无常

    算法训练 黑白无常 时间限制:1.0s 内存限制:256.0MB 问题描述 某寝室的同学们在学术完之后准备玩一个游戏:游戏是这样的,每个人头上都被贴了一张白色或者黑色的纸,现在每个人都会说一句话&qu ...

  5. Java实现 蓝桥杯 数独游戏

    你一定听说过"数独"游戏. 如图,玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行.每一列.每一个同色九宫内的数字均含1-9,不重复. 数独的答案都是唯一 ...

  6. Python爬虫之request +re

    什么是爬虫? 它是指向网站发起请求,获取资源后分析并提取有用数据的程序: 爬虫的步骤: 1.发起请求 使用http库向目标站点发起请求,即发送一个Request Request包含:请求头.请求体等 ...

  7. 关于C#委托三种调用的分享

    一.同步调用 1.同步调用会按照代码顺序来执行2.同步调用会阻塞线程,如果是要调用一项繁重的工作(如大量IO操作),可能会让程序停顿很长时间,造成糟糕的用户体验,这时候异步调用就很有必要了. 举个栗子 ...

  8. Netty源码学习系列之4-ServerBootstrap的bind方法

    前言 今天研究ServerBootstrap的bind方法,该方法可以说是netty的重中之重.核心中的核心.前两节的NioEventLoopGroup和ServerBootstrap的初始化就是为b ...

  9. 温故知新-Mysql的体系结构概览&sql优化步骤

    文章目录 Mysql的体系结构概览 连接层 服务层 引擎层 存储层 存储引擎 存储引擎概述 存储引擎特性![存储引擎特性对比](https://img-blog.csdnimg.cn/20200510 ...

  10. Android开发之修改Manifest中meta-data的数据

    代码 private void initFMMap() { ApplicationInfo appInfo = null; try { appInfo = this.getPackageManager ...