Spring特性之一——AOP面向切面编程
Posted 苍山有雪,剑有霜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring特性之一——AOP面向切面编程相关的知识,希望对你有一定的参考价值。
带着问题去阅读
- 什么是面向切面编程?(是什么+为什么)
- 如何使用AOP?(怎么用)
什么是AOP?
AOP,全称:Aspect Oriented Programming,即面向切面编程。它最早是在1997年的面向对象编程大会上提出来的概念,并于2001年在AspectJ中得到首次实践。
与面向对象OOP不同的是,AOP并不是将程序抽象成各个层次的对象,而是将程序抽象成一个一个的切面。
何为切面?
简单的理解,就是将程序在一些特定的地点(比如在某个函数调用之前、返回之后等)切分开来,并在这些特定的地点插入一些程序片段,从而实现代码复用、逻辑判断等。
那,为什么要这么做?
先看下面这幅图:
三个Service服务都需要进行安全检查、事务执行、其他处理,这三个必备而通用的步骤。
在传统的面向过程的编程中,直接复制相同代码肯定是不可取的,稍微高明的做法是将**这段相同的代码提取为一个方法,**而后在需要使用的地方去调用这个方法。但当之后新增一个需求或删减需求时,都得去调用的地方进行更改,会造成一定的时间开销。
其实我们可以这样看:三个Service在执行到一定的过程时,被拦腰斩断,强行插入了安全、事务、其他这三个执行环节,而不会影响这些程序之后的运行。
这就是对AOP的简单理解,要想进一步理解就得靠之后的例子以及经常的使用。
AOP经常被用来进行安全检查、打印日志、运行监控等功能。
在介绍如何使用AOP之前,需要提前了解一下AOP的有关术语。
AOP术语
AOP的术语是围绕“切面”这个核心概念所设计的。
- 连接点(JoinPoint)
连接点是指程序执行过程中的特定位置,比如方法调用前、后、抛出异常等。
连接点=执行主体+具体位置。
举个例子,Student这个类中有一个方法getName()。
那么Student.getName()就是一个执行主体,它存在多个具体位置:before、after、around、return等。
意思就是在getName()方法执行前、后、前后、返回后再执行想要插入的代码逻辑(就是强行加进去的代码)。
这些连接点有什么用?
它表明了在程序的那些地方可以植入(术语叫做——织入)代码,即——见缝插针!
- 通知(Advice)
通知这个概念需要和连接点相结合来理解:通知就是告诉将要执行的植入代码,某个连接点已经触发了,你要执行就赶紧!
通过通知(也成增强点或者横切关注点),可以使得在特定的连接点执行特定的代码。
Spring现在有五类通知:
- 切入点(PointCut)
切入点的概念其实是一个过滤的条件,是用来找到连接点的执行主体——一个切入点对应多个连接点(因为连接点存在之前、之后等情况)。
- 通知器(Advisor)
通知器=切入点+通知。
简单理解为一个触发器+执行器。
- 切面(Aspect)
切面=切入点+通知。
跟通知器的区别就在于,切面无需实现通知接口(看代码),但配置文件中需要写明;但通知器需要实现通知接口。
- 织入(Weaving)
将一部分代码强行插入到执行程序中,就是所谓的织入。
PS:术语的英译之后较难理解,还是结合代码领会其意思即可。
如何使用AOP?
这里借用SharpCJ所写博客中的例子来帮助理解AOP中的术语以及具体的使用方式:
现在有一个IBuy接口:
package com.sharpcj.aopdemo.test1;
public interface IBuy {
String buy();
}
Boy和Girl实现了这个接口:
package com.sharpcj.aopdemo.test1;
import org.springframework.stereotype.Component;
@Component
public class Boy implements IBuy {
@Override
public String buy() {
System.out.println("男孩买了一个游戏机");
return "游戏机";
}
}
和
package com.sharpcj.aopdemo.test1;
import org.springframework.stereotype.Component;
@Component
public class Girl implements IBuy {
@Override
public String buy() {
System.out.println("女孩买了一件漂亮的衣服");
return "衣服";
}
}
编写了一个测试类:
package com.sharpcj.aopdemo;
import com.sharpcj.aopdemo.test1.Boy;
import com.sharpcj.aopdemo.test1.Girl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AppTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(AppConfig.class);
Boy boy = context.getBean("boy",Boy.class);
Girl girl = (Girl) context.getBean("girl");
boy.buy();
girl.buy();
}
}
结果为:
那么,如何使用切面?
先定义一个切面类,BuyAspectJ.java
package com.sharpcj.aopdemo.test1;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class BuyAspectJ {
@Before("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..))")
public void haha(){
System.out.println("男孩女孩都买自己喜欢的东西");
}
}
这里的注解@AspectJ就表示这个类是一个切面(切面就是一个切入点+通知),与此同时(“execution(* com.sharpcj.aopdemo.test1.IBuy.buy(…))”)声明了切点是执行buy()方法,@Before表示在这个方法执行之前。
再次运行一下,结果为:
可以看到,与之前的结果相比,程序执行过程中插入了切面类中的方法!
关于AOP进一步的学习()(比如AOP注解、XML配置等等)可以直接去看AOP的官方文档,或者参考资料。
与OOP的关系
需要注意的是AOP与OOP并不存在谁高谁低,非此即彼,AOP可以认为是对OOP的补充(要知道,AOP是在OOP大会上提出来的!)。
OOP封装的是方法和属性,是逻辑对象层面的概念;
而AOP封装的是一些通用的业务,面向的是某个步骤或者环节,从而实现各个环节之间的松耦合。
唯有两者的结合才可以使得彼此更为强大,一如它们所构建的框架——Spring。
参考资料
以上是关于Spring特性之一——AOP面向切面编程的主要内容,如果未能解决你的问题,请参考以下文章