Spring AOP 介绍与基于接口的实现
热烈推荐:超多IT资源,尽在798资源网
声明:转载文章,为防止丢失所以做此备份。
本文来自公众号:程序之心
原文地址:https://mp.weixin.qq.com/s/vo94gVyTss0LYwEcRx4iiw
面向切面编程,缩写为 AOP,在程序开发中主要用来解决一些系统层面上的问题,比如日志、事务、权限等。在阿里体系中,AOP
广泛应用于天梭日志、本地缓存、doom 增强等场景。
AOP基本概念
为什么需要面向切面编程?面向对象编程解决了封装问题,但同时也带来了新问题,如何增强对象的方法?比如,一个接口 A 可能有多个实现类 A1、A2、******、An,如何为多个实现类的同一个方法打印日志或者做权限管理?普通的面向对象思路一般是封装一个工具类,然后加到所有方法里,一旦需要做的增强比较多代码就会很臃肿,难以维护。因此,才有了面向切面编程。
下面的图展示了面向切面编程的思想,面向对象编程通过封装、继承和多态实现了业务逻辑,而面向切面编程把业务流程横刀切开在切面上处理特定事务。一横一竖,切面的称呼就是这样来的。
从上图也可以看出面向切面编程不属于业务逻辑的一部分,而是与具体业务无关的特定事务,如日志、权限等。面向切面编程有以下几个概念需要理解:
- (1)Aspect(切面):通常是一个类,里面可以定义切入点和通知;
- (2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用;
- (3)Advice(通知):AOP在特定的切入点上执行的增强处理,可以是前置处理、后置处理、异常处理等;
- (4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式;
- (5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。
- (6)织入:把切面应用到目标对象来创建新的代理对象的过程。
织入一般发生在如下几个时机:
- (1)编译时:当一个类文件被编译时进行织入,这需要特殊的编译器才可以做的到,例如AspectJ的织入编译器;
- (2)类加载时:使用特殊的ClassLoader在目标类被加载到程序之前增强类的字节代码;
- (3)运行时:切面在运行的某个时刻被织入。
Spring AOP
Spring 提供了专门的依赖包来支持 AOP 。Spring中的AOP代理可以是JDK动态代理,也可以是CGLIB代理。代理的生成,管理及其依赖关系都是由IOC容器负责,Spring默认使用JDK动态代理,在需要代理类而不是代理接口的时候,Spring会自动切换为使用CGLIB代理。
Spring 提供了多种实现AOP的方式:
- 基于接口实现的切面:实现接口的方法,定义切入点和通知;
- 基于注解的切面:基于 @Aspect、@Pointcut、@Before、@AfterReturning 等注解的 AOP 方式;
- 基于 XML 的切面:使用 xml 中的 aop 命名空间,如 aop:aspect;
这里介绍使用比较多比较简单的基于接口方式,其他几种类型不做介绍。Spring 使用 Advisor 接口表示一般切面,包含了 Advice,但是没有切入点。
public interface Advisor {
//获取 Advice
Advice getAdvice();
//暂不用
boolean isPerInstance();
}
PointcutAdvisor 接口继承了 Advisor,代表具有切入点的切面,它包含Advice 和 Pointcut 两个类。基于 PointcutAdvisor 接口即可定义切面,可以通过类、方法名、注解等信息灵活地定义切面的连接点,提供更具适用性的切面。
public interface PointcutAdvisor extends Advisor {
//获取 Pointcut
Pointcut getPointcut();
}
Spring 提供了 PointcutAdvisor 接口的 6 个实现类,定义了 6 种切面类型,如下:
- DefaultPointcutAdvisor:最常用的切面类型,它可以通过任意Pointcut和Advice定义一个切面;
- NameMatchMethodPointcutAdvisor:通过该类可以定义按方法名定义切点的切面:
- RegexpMethodPointcutAdvisor:对于按正则表达式匹配方法名进行切点定义的切面,可以通过扩展该实现类进行操作;
- StaticMethodMatcherPointcutAdvisor:静态方法匹配器切点定义的切面;
- AspecJExpressionPointcutAdvisor:用于Aspecj切点表达式定义切点的切面;
- AspecJPointcutAdvisor:用于AspecJ语法定义切点的切面。
Spring AOP 提供了 Pointcut 接口多种内置实现,我们可以基于这些实现定义切入点。常用的实现包括:
- StaticMethodMatcherPointcut:静态匹配方法,实现方法级别的切入,非运行时切入,默认情况下匹配所有的类;
- DynamicMethodMatcherPointcut:动态匹配方法,实现方法级别的切入,运行时切入,默认情况下匹配所有的类;
- AnnotationMatchingPointcut:基于注解匹配;
- ExpressionPointcut:支持AspectJ切点表达式语法;
- ControlFlowPointcut:控制流程切点,根据程序执行堆栈的信息查看目标方法是否由某一个方法直接或间接发起调用,以此判断是否为匹配的连接点;
- ComposablePointcut:复合切点,为创建多个切点而提供的方便操作类。它所有的方法都返回ComposablePointcut类,这样,我们就可以使用链接表达式对其进行操作。
Spring AOP 提供了 Advice 接口多个子接口来支持增强。如下所示:
- 接口 MethodBeforeAdvice:在目标方法调用之前调用的Advice;
- 接口 AfterReturningAdvice:在目标方法调用并返回之后调用的Advice;
- 接口 MethodInterceptor:在目标方法的整个执行前后有效,并且有能力控制目标方法的执行;
- 接口 ThrowsAdvice:在目标方法抛出异常时调用的Advice;
基于接口的AOP使用方式
基于 PointcutAdvisor 接口实现 AOP 只需要定义切入点 Pointcut 和通知 Advice 即可,其他交给 Spring AOP 框架去处理。在基于接口的实现中,PointcutAdvisor 的实现类定义了一个切面。
在 getPointcut 中定义切入点。如下面的示例,定义了切入点是所有拥有 MyTestAnnotation 注解的方法,凡是有注解的方法都是我们的切入点。
@Getter
public Pointcut pointcut = new StaticMethodMatcherPointcut() {
@Override
public boolean matches(Method method, Class<?> targetClass) {
return method.getAnnotation(MyTestAnnotation.class) != null;
}
};
在 getAdvice() 中定义需要做的增强。如下面的示例,实现了 MethodInterceptor 接口来进行方法增强,入参为 MethodInvocation 对象,该对象携带了切面的信息,如正在调用的方法、入参等。可以在方法中直接调用原来的方法,并在调用方法前进行前置处理,或者在调用方法后进行后置处理。
@Getter
public Advice advice = (MethodInterceptor)methodInvocation -> {
// TODO 增强前置处理
// 调用原来的方法
Object result = methodInvocation.proceed();
// TODO 增强后置处理
return result;
};
AOP注意事项
- AOP 不宜处理耗时太久的操作:AOP 作为切面应该专注于处理简单的事务,如打印日志。耗时过多的操作不宜放在 AOP
中进行,如果一定需要处理,应该做异步处理。 - AOP 不宜抛出异常:AOP 的操作不能影响正常的业务逻辑,因此一定要加 catch,确保 AOP 本身的异常不影响正常业务。
- AOP 不能出现循环:尤其是打印日志的切面,一定要避免循环。AOP 中出现错误需要打印日志的时候,尽量单独打印,避免循环。
总结
本文介绍了 AOP 基本概念,介绍了基于 Spring AOP 接口实现面向切面编程的方法。
合理地使用 AOP 可以降低系统复杂度,无侵入地增强系统的功能,在 Java 企业应用中有着广泛的应用。
Spring AOP 介绍与基于接口的实现的更多相关文章
- Spring AOP介绍与使用
Spring AOP介绍与使用 AOP:Aspect Oriented Programming 面向切面编程 OOP:Object Oriented Programming 面向对象编程 面向切面 ...
- Spring AOP介绍
1.介绍 AOP(面向切面编程)对OOP(面向对象编程)是一种补充,它提供了另一种程序结构的思路.OOP的模块单元是class,而AOP的模块单元是aspect.Spring中一个关键的组件是AOP框 ...
- Spring AOP介绍及源码分析
转自:http://www.uml.org.cn/j2ee/201301102.asp 软件开发经历了从汇编语言到高级语言和从过程化编程到面向对象编程:前者是为了提高开发效率,而后者则使用了归纳法,把 ...
- spring aop介绍和示例
参考:<Spring in Action> 一.AOP介绍 AOP是Aspect Oriented Programming的缩写,意思是面向切面编程. 应用中有一些功能使用非常普遍,比如事 ...
- Spring AOP 创建Advice 基于Annotation
public interface IHello { public void sayHello(String str); } public class Hello implements IHello { ...
- Spring Aop(十五)——Aop原理之Advised接口
转发地址:https://www.iteye.com/blog/elim-2398726 Spring Aop原理之Advised接口 通过之前我们介绍的ProxyFactory我们知道,Spring ...
- Spring Aop(七)——基于XML配置的Spring Aop
转发:https://www.iteye.com/blog/elim-2396043 7 基于XML配置的Spring AOP 基于XML配置的Spring AOP需要引入AOP配置的Schema,然 ...
- 基于代理类实现Spring AOP
目录 ProxyFactoryBean类介绍 基于JDK动态代理的Spring AOP实现 基于CGLIB代理的Spring AOP实现 Spring的通知类型 ProxyFactoryBean类 ...
- Spring AOP 和 动态代理技术
AOP 是什么东西 首先来说 AOP 并不是 Spring 框架的核心技术之一,AOP 全称 Aspect Orient Programming,即面向切面的编程.其要解决的问题就是在不改变源代码的情 ...
随机推荐
- 【codeforces 798C】Mike and gcd problem
[题目链接]:http://codeforces.com/contest/798/problem/C [题意] 给你n个数字; 要求你进行若干次操作; 每次操作对第i和第i+1个位置的数字进行; 将 ...
- 【[Offer收割]编程练习赛15 C】过河问题
[题目链接]:http://hihocoder.com/problemset/problem/1516 [题意] [题解] 状态压缩DP+bfs 这个过河问题能用bfs来搞.涨知识了; 首先; 16个 ...
- POJ - 3126 - Prime
先上题目 Prime Path Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9259 Accepted: 5274 D ...
- 0622通过插件的方式来热安装sphinx
1.查看当前运行的mysql版本 mysqldump --version 我的Mysql版本5.5.32 2.下载对应的mysql 5.5.32 (版本号一定不能错,要不安装不成功)源码,并解压 下载 ...
- 一个简单的ant应用
<pre name="code" class="html"><?xml version="1.0" encoding=&q ...
- leetcode || 50、Pow(x, n)
problem: Implement pow(x, n). Hide Tags Math Binary Search 题意:求x的n次幂 thinking: (1)最简单想到的是直观上的数学幂函数求法 ...
- 1、应用设置之TAB页
转载请注明出处:http://blog.csdn.net/droyon/article/details/39891257 应用设置的TAB页,共分6页.如图 ...
- POJ 3126 Prime Path SPFA
http://poj.org/problem? id=3126 题目大意: 给你两个四位的素数s和t,要求每次改变一个数字.使得改变后的数字也为素数,求s变化到t的最少变化次数. 思路: 首先求出全部 ...
- 一步一步跟我学习lucene(18)---lucene索引时join和查询时join使用演示样例
了解sql的朋友都知道,我们在查询的时候能够採用join查询,即对有一定关联关系的对象进行联合查询来对多维的数据进行整理.这个联合查询的方式挺方便的.跟我们现实生活中的托人找关系类似,我们想要完毕一件 ...
- Swift_ios_二进制,十进制,十六进制之间的转换
这里所说的转换,并不是Swift中字面量之间的转换.如果是字面量之间的转换,ios系统中已经自动帮我们转换了. 例如let number1:Int = 8let number2:Int = 0b100 ...