Spring学习教程之AOP模块的概述
作者:张涛 发布时间:2022-06-04 00:17:13
概述
spirng-aop模块是Spring框架中的核心模块,虽然Spring Ioc container并不依赖AOP,但AOP给Ioc的实现提供了一种强大而灵活的解决方案。
在Spring Framework中,AOP主要是用于两种目的:
提供一些 企业 级的声明式服务,典型的应用如 declarative transaction management .
允许用户实现自己的aspects,用AOP的方式来帮助和补充OOP的功能及实现
AOP从功能的角度来讲,可能看作OOP编程方式的一种补充,提供了一种不同的代码或者系统组织方式。OOP中的核心概念是Class,而在AOP中则是Aspect。
spirng-aop模块是Spring框架中的核心模块,虽然Spring Ioc container并不依赖AOP,但AOP给Ioc的实现提供了一种强大而灵活的解决方案。
在Spring Framework中,AOP主要是用于两种目的:
提供一些企业级的声明式服务,典型的应用如 declarative transaction management.
允许用户实现自己的aspects,用AOP的方式来帮助和补充OOP的功能及实现
Spring AOP由纯Java实现,无须特殊的编译处理,也不需要控制类加载器的层次结构,所以它可以适用于Servlet Container和其它application server.
Spring AOP目前只支持方法级别的切换或拦截,属性的拦截现在不支持,如果想要拦截属性,可以考虑使用AspectJ语言。
Spring AOP的使用不同于其它大多数AOP框架。它的主要目的不是提供一套大而全的AOP实现,而是集成AOP不同实现协同Spring Ioc来帮助解决一些普遍性问题。
需要注意的是,一些细粒度的advised(如domain model),Spring AOP往往不能提供很好的支持,这场景也还是考虑AspectJ。即使如此,就普遍经验来说Spring AOP的强大机制依然能够解决大多数场景的问题。
那么该如何看待Spring AOP和AspectJ,引用Spring官方文档的原文:
Spring AOP will never strive to compete with AspectJ to provide a comprehensive AOP solution. We believe that both proxy-based frameworks like Spring AOP and full-blown frameworks such as AspectJ are valuable, and that they are complementary, rather than in competition. Spring seamlessly integrates Spring AOP and IoC with AspectJ, to enable all uses of AOP to be catered for within a consistent Spring-based application architecture. This integration does not affect the Spring AOP API or the AOP Alliance API: Spring AOP remains backward-compatible.
在Spring框架所有的模块设计中,始终遵守的核心信条之一是——无侵入性。
所以在使用Spring AOP时,不会强制我们在业务代码中引入特定类或者接口,可以最大限度的保持代码 clean and decouple。然而Spring也提供了另一种选择,如果有特定的场景需要的话,你可以在你的代码中直接引入Spring AOP。几乎所有Spring框架中的模块,在使用的方式上都会给你多种选择,以便让用户选择更适合自己场景的方式。使用AspectJ还是Spring AOP,使用annotation方式还是xml的配置方式,Depends On U。
了解了Spring AOP的初衷和使用场景,来看下它的大致实现原理
在软件世界中的绝大多数问题,都可以通过加一层来解决。
这里所说的层,当然是广义上的,可以是一层抽象,也可以是一层cache,大致含义是隔离和解耦的范畴。
在Spring的世界里,每一个模块的引入,或者第三方技术的集成,总会提供一个抽象层 ,对用户提供统一的API,屏蔽了所有的实现细节以及不同实现的差异。例如spring-cache,spring-jdbc,spring-jms以及spirng-messaging等模块都提供了一层抽象。
Spring AOP的实现是基于代理的机制,默认是采用Jdk dynamic proxy,也可以采用cglib的proxy。两者的区别主要是在于被代理的对象的不同。当目标对象是接口时,Jdk dynamic proxy可以完成代理,但目标对象是没有实现接口的类时(尽量少一些,面向接口编程是好习惯),是需要采用cglib proxy来完成代理的,当然你也可以强制接口也采用cglib来代理;另外需要注入或引用具体类型时,如果引用的东西恰恰是代理过的对象,此时也需要采用cglib的方式。
功能设计和实现上来可以分为两大块
aop基础设施的创建,可以看作是aopProxy的生成
aopProxy对象的调用时的处理拦截,即处理对目标对象的 *
AOP的创建
生成代理对象的核心类,ProxyFactoryBean getObjecct()
下图是生成代理时,是用Jdk还是cglib的选择逻辑:
找到了生成代理的具体执行者,那么这个操作是在什么时候被调用的呢,了解过Spring bean生命周期的都应该知道,bean在创建的时候,有一系列的回调接口供用户插入自定义的行为,来左右bean的一些特性,其中BeanPostProcessor是接口中的一种。以往的文章有介绍过(玩转Spring bean的终极利器)。而Spring AOP正是利用这个契机,在创建bean的过程中插了一手,如果正在创建的bean是我们aop的target,则创建代理,并最终把代理对象返回给Ioc。
AbstractAutoProxyCreator 这个类是一个BeanPostProcessor的实现,用来创建代理,来看这个处理器的后处理方法,最终是返回了createProxy()方法返回的代理
AOP切面的增强的执行
可以理解成对目标对象上所有 * 链的调用
由于Spring AOP的代理具体实现有两种,JDK dynamic proxy和cglib,所以执行 * 的方式有所不同,具体可以阅读源码JdkDynamicAopProxy类的invoke方法
对目标方法的调用最终是依靠ReflectiveMethodInvocation.
ReflectiveMethodInvocation中的proceed处理是采用递归的方式处理 * 链
CglibAopProxy的 intercept方法
CglibMethodInvoation是继承了ReflectiveMethodInvocation,处理 * 链也是用的上边的proceed()方法。
在使用Spring AOP时需要注意的两点细节:
1、在类内部的方法调用时(self-invoke),Spring AOP不起作用,原因是内部调用没通过代理对象,直接使用的目标对象。解决方法有:
重构代码,避免内部调用
AopContext.currentProxy()
或者干脆使用AspectJ语言吧...
2、在注入bean时,如果想注入bean的具体的类型而不是接口,那么采用cglib吧
Spring AOP的功能很强大,设计巧妙,这里梳理了主要脉络,细节不再一一讨论。
来源:https://mp.weixin.qq.com/s/XkSpuDCrx3nWSOBhQqAm9g


猜你喜欢
- 使用方法:先把mvcpager.dll引用加入mvc项目中。前台代码前台:@{Layout = null;}@using Webdiyer.
- 准备:(1) IDEA 2021(2)Java 1.8(3)数据库 MySQL 5.7 (SQLyog 或 Navicat)在 MySQL
- 本文实例为大家分享了Android实现连连看游戏的具体代码,供大家参考,具体内容如下本人用 android studio 实现的源码主活动
- 数据校验在web应用里是非常重要的功能,尤其是在表单输入中。在这里采用Hibernate-Vapdator进行校验,该方法实现了JSR-30
- 本文实例讲述了C#实现对二维数组排序的方法。分享给大家供大家参考。具体实现方法如下:/// <summary>/// A gen
- 某些情况下我们可能需要与Mysql或者Oracle数据库进行数据交互,有些朋友的第一反应就是直接在Android中加载驱动然后进行数据的增删
- 二叉树的深度题目:输入一颗二叉树的根节点,求该树的的深度。输入一颗二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点
- 1. Spring简介Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架。2. Spring的优势 1.方便解耦, 简
- 前言虽然Aandroid目前已经有RecyclerView了、非常强大的一个View、可以直接控制成ListView以及GridView等、
- 背景朋友想从XX超市app购买一些物美价廉的东西,但是因为人多货少经常都是缺货的状态,订阅了到货通知也没什么效果,每次收到短信通知进入app
- 在最近的项目中有个需求是这样的:入参封装成JSON,EXAMPLE:{ "uuid": "iamauuid&q
- ReferenceWhy using finalizers is a bad idea当在一个类中使用了另外一个实现了IDisposable
- Redis缓存中间件缓存是什么  所谓缓存就是数据交换的缓冲区(称作Cache [ k&aeli
- flutter组件的实现参考了react的设计理念,界面上所有的内容都是由组件构成,同时也有状态组件和无状态组件之分,这里简单介绍最基本的组
- 1.基本语法key: value;kv之间有空格大小写敏感使用缩进表示层级关系缩进不允许使用tab,只允许空格缩进的空格数不重要,只要相同层
- 项目要用到Webview和js交互,查了查以前的项目感觉还是有必要整理下的。 简单描述下项目中用到的地方,比如说在web页需要用到登录的地方
- 本教程为大家分享了学籍管理系统的具体java代码,供大家参考,具体内容如下1.需求分析 1.1系统功能设计 (1)能够查询学生的基本信息,如
- 本文实例为大家分享了Java实现分页功能的具体代码,供大家参考,具体内容如下不用根据改变SQL的形式去查询; 直接查询所有的数据,根据页码自
- 在style中如下面那样定义:<style name="mystyle"> <item name=&
- 本文以实例形式详细讲述了Java的反射机制,是Java程序设计中重要的技巧。分享给大家供大家参考。具体分析如下:首先,Reflection是