看了绝对不会后悔之:spring AOP原理

引子:上一篇文章已经讲了spring的核心思想Ioc,那作为spring的两大核心思想的另一个思想Aop,当然也不能缺席啦。

那么,什么是Aop呢?

我们都知道Java的核心思想是面向对象OOP,而OOP的核心是封装、继承、多态。

什么是封装?

封装就是把对象的属性和操作(或服务)结合为一个独立的整体,并尽可能隐藏对象的内部实现细节。

由此可见封装的好处在于把整个项目中相同的业务抽成成一个个独立的类/方法,使得相同的代码有复用性,这样的做法可以降低代码的复杂度,但是也存在一些问题,比如我们都知道日志是开发中必不可少的逻辑,当我们把一块块的代码封装到不同的类中之后,一旦需要添加日志时,就需要在每个类中都写入相应的日志代码,有人会说,可以把日志代码封装成一个类来调用,在这些需要日志的类中调用日志收集的方法即可,但这样一来,日志类和业务逻辑就产生了耦合,当日志类发生变化时,导致业务逻辑的代码都需要修改。

这..怎么办呢?

当OOP满足不了的时候,AOP就来救场了。

AOP:面向切面编程,作为OOP编程的一种补充,它的核心思想是在运行时动态地将代码切入到类的指定方法、指定位置上。

因此问题就解决,我们把日志收集逻辑作为一个切面,切入到指定的类/方法中,按照我们需求执行即可,我们的业务逻辑既不会因为这个日志类产生变动而收到影响,也不会因为它的存在而产生耦合现象。

知道原理就好办了,下面我们来举个栗子:

例如:很多时候,API的每个接口,我们都需要知道它的执行时间,这样方便我们做性能监控和优化

下面是常规操作:

1publicclassApi{

2publicvoidtest(){

3// 开始

4longbegin=(newDate()).getTime();

5System.out.println("开始执行....");

6

7//执行业务逻辑

8

9// 结束

10longend=(newDate()).getTime();

11//统计耗时

12System.out.println("结束执行....");

13System.out.println(" 执行完成,耗时:"+(end-begin)+"毫秒");

14}

15}

可以看到,这样确实可以获取到执行时长,但问题是,每个方法都要加入这些代码,那就很悲催了。。

下面,我们用spring的AOP来实现同样的功能

首先,创建一个切面的类:

1packagecom.jaybril.aoptest;

2

3importjava.util.Date;

4

5importorg.aspectj.lang.ProceedingJoinPoint;

6importorg.aspectj.lang.annotation.Around;

7importorg.aspectj.lang.annotation.Aspect;

8importorg.aspectj.lang.annotation.Pointcut;

9importorg.springframework.stereotype.Component;

10importorg.springframework.util.StopWatch;

11

12

13@Component

14@Aspect

15publicclassAopAspect{

16//within 用于匹配指定类型内的方法执行

17//设置切入点

18@Pointcut("within(AopService)")

19//切点签名方法,作用是使得通知的注解可以通过这个切点签名方法连接到切点,

20//通过解释切点表达式找到需要被切入的连接点。

21//最终的目的都是为了找到需要被切入的连接点

22publicvoidpointcut(){

23System.out.println("I am pointcut...");

24}

25//    @Before:前置通知,在调用目标方法之前执行通知定义的任务

26//    @After:后置通知,在目标方法执行结束后,无论执行结果如何都执行通知定义的任务

27//    @After-returning:后置通知,在目标方法执行结束后,如果执行成功,则执行通知定义的任务

28//    @After-throwing:异常通知,如果目标方法执行过程中抛出异常,则执行通知定义的任务

29//    @Around:环绕通知,在目标方法执行前和执行后,都需要执行通知定义的任务

30@Around("pointcut()")

31publicObjectinvokeMethod(ProceedingJoinPoint pjp)throwsThrowable{

32// 开始

33longbegin=(newDate()).getTime();

34System.out.println("开始执行....");

35//执行业务逻辑

36Object retVal = pjp.proceed();

37// 结束

38longend=(newDate()).getTime();

39//统计耗时

40System.out.println("结束执行....");

41System.out.println("方法:"+pjp.getSignature().toShortString()+" 执行完成,耗时:"+(end-begin)+"毫秒");

42returnretVal;

43}

44

45}

其次,创建一个业务类:

1packagecom.jaybril.aoptest;

2importorg.springframework.stereotype.Service;

3@Service

4publicclassAopService{

5publicvoidtest(){

6System.out.println("执行业务逻辑。。。");

7}

8}

接下来,我们测试一下:

1packagecom.jaybril.aoptest;

2importjavax.annotation.PostConstruct;

3importorg.springframework.beans.factory.annotation.Autowired;

4importorg.springframework.boot.SpringApplication;

5importorg.springframework.boot.autoconfigure.SpringBootApplication;

6importorg.springframework.context.annotation.EnableAspectJAutoProxy;

7

8@EnableAspectJAutoProxy//开启AOP

9@SpringBootApplication//把启动类注入到容器

10publicclassAopTest{

11@Autowired

12AopService service;

13publicstaticvoidmain(String[] args){

14SpringApplication.run(AopTest.class, args);

15}

16@PostConstruct//用于在依赖关系注入完成之后需要执行的方法上,以执行任何初始化

17publicvoidtest(){

18service.test();

19}

20@PostConstruct

21publicvoidtest2(){

22service.test();

23}

24}

看看输出:

1开始执行....

2执行业务逻辑。。。

3结束执行....

4方法:AopService.test() 执行完成,耗时:17毫秒

5开始执行....

6执行业务逻辑。。。

7结束执行....

8方法:AopService.test() 执行完成,耗时:0毫秒

可以清楚的看到,它按照我们的预想输出了,而我们的业务类,没有任何日志的代码侵入,并且日志类的变动,也不会对业务类产生影响,因此,这就是AOP的优势之处。

本文只是用了一些通俗的话语来简述AOP的原理,并且用一个最常见最简单的例子来分析理解AOP,实际上AOP还有非常多的知识点和用途,这就要求大家多学多写了。

觉得本文对你有帮助?请分享给更多人

关注「编程无界」,提升装逼技能

![image](http://upload-images.jianshu.io/upload_images/13318651-42fdcc48cd3a1eca?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345