Spring学习之AOP基础

Spring学习之AOP基础

前言

最近在学Spring,这两天碰到AOP这个概念,一开始不是很理解其背后的思想,经过这两天的学习,基本上大致理解了其含义以及目的,故将学习过程的笔记整理出来,以供日后回顾使用,以及与各位正在学习Spring的朋友分享

AOP的介绍

AOP,全程是Apsect Orientation Programming,翻译过来就是面向切面的编程,说到面向切面,首先需要谈到的就是OOP,也就是比较熟悉的面向对象编程,在面向对象编程中,当重复性的代码出现比较多次的时候,一般我们就会将公共部分其抽取出来,形成父类,这样,通过继承的手段,就能极大地减少代码的重复。然而,在实际开发过程中却有一些代码是冗余是,但是通过面向对象开发的方式却是无法将其抽取出来,比如说,上一篇文章中提到的,日志管理,或者常用的事务管理等,这些类型的代码有具有一个很明显的特点,那就是他们紧紧围绕在业务代码,或者说目标代码的周围(前/后),这种形式的代码采用面向对象的方式是无法进行抽取的。于是,需求诞生了解决方案,面向切面的方式就开始投入了使用。

所谓的面向切面编程,其实就是从横向的角度来处理冗余的代码(面向对象的编程方式基本都是纵向的角度),比如说,日志管理,由于日志管理代码紧紧围绕在业务代码中,从横向的角度来看这些代码,日志管理代码就好像是一层外衣,紧紧地包围着业务代码,而面向切面编程的核心思想,就是将这些具有横向特征的代码抽取出来,并且将他们集中在特定的类中,然后通过织入的方式,将他们织入到对应的业务方法中,这样子,这些代码就好像是一层独立与业务代码的代码了,而将他们抽取出来并且在需要的时候将他们整合进去的方式,就是面向切面编程了。

这里需要注意一点,面向切面编程的出现,不是要替代面向对象编程,而是对其进行补充,扩展面向对象编程的能力。在前面的一小节,动态代理中也提到了,动态代理技术是Spring中AOP应用的背景,也就是说,Spring是通过动态代理技术来实现面向切面编程的,有了动态代理技术的基础,接下来我们就来学习面向切面编程

AOP编程常用术语

在具体学习AOP编程之间,有几个比较重要的概念需要弄清楚,这几个概念是面向切面编程的基础,也是其核心。

  • 连接点 Jointpoint
    • 所谓的连接点,指的是代码中可以进行增强的点,比如说方法调用前、方法调用后、方法调用前后、类初始化前、类初始化后、异常抛出后
  • 切点 Cutpoint
    • 切点,是指要进行增强的点,这里需要注意区分连接点和切点,连接点是所有符合条件的点,而切点是所要进行织入的点,连接点包含了切点,但同时一个切点可能匹配多个连接点
  • 增强 Advice
    • 增强,指的是所要在切点上执行的代码,也就是具体的想要增强的代码,一般还包含了方位信息(方法前/后、返回等,但不包含具体的方法信息,也就是不包含切点信息)
  • 目标类 Target
    • 目标类,指的是所要进行增强的类,这个比较好理解
  • 引介 Introduction:
    • 引介,一种特殊的增强,主要作用于类级别上,通常用于为类动态实现接口等的操作,也就是作用于类上的增强
  • 织入 Weaving
    • 织入,指的是将通过切点信息,将对象的增强添加到目标类的过程
  • 代理 Proxy
    • 代理,这个比较好理解,指的就是通过增强之后所产生的对象,也就是原来目标类经过增强之后的代理类
  • 切面 Aspect:
    • 切面,由切点和增强组成,包含了横切逻辑和方位的定义,一个切点可以描述多个连接点,加上增强,就形成了面,也就是所谓的切面了。

原始的Spring AOP编程方式

这里通过比较原始的Spring AOP编程方式来详细讲解上面所提到的概念,以增强对上面的概念的认识,需要注意的是,通过这种方式的目的是为了更好地理解AOP编程的概念,在日常的开发过程中,由于这种方式比较底层,而且操作麻烦,基本是不怎么使用的,还有一点需要注意的是,Spring仅支持方法的增强,也就是说,Spring中的切点只能描述方法,增强只能作用在方法上。


/**
 * 方法调用前增强
 */
class LogManager implements MethodBeforeAdvice{

    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("log something");
    }
}

/**
 * UserService接口
 */
interface UserService{

    void login();
    void logout();
}

/**
 * UseService实现类
 */
class UserServiceImpl implements UserService{

    @Override
    public void login() {
        System.out.println("someone login....");
    }

    @Override
    public void logout() {
        System.out.println("someone logout....");
    }
}

对应的Spring配置文件如下


    <bean id="userServiceTarget" class="cn.xuhuanfeng.aop.UserServiceImpl"/>
    <bean id="advice" class="cn.xuhuanfeng.aop.LogManager"/>
    <!--指定代理类,用于为目标类进行增强-->
    <bean id="userService" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--配置对应的目标类,也就是要对其进行增强的类-->
        <property name="target" ref="userServiceTarget"/>
        <!--配置对应的增强类-->
        <property name="interceptorNames" value="advice"/>
        <!--是否使用CGLib动态代理,如果没有配置接口,则默认是-->
        <property name="optimize" value="true"/>
    </bean>

测试结果如下所示


log something
someone login....
log something
someone logout....

从上面的结果可以看出,我们已经成功为UserService的方法配置增强,并且UserService对此并不知情

接下来再看另外几个例子


/**
 *  方法调用后增强
 */
class LogManagerAfter implements AfterReturningAdvice{

    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("after returning");
    }
}

/**
 * 环绕增强
 */
class LogManagerAround implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("before ...");
        Object object = methodInvocation.proceed();
        System.out.println("after ...");
        return object;
    }
}

在配置文件中进行配置的具体代码基本同上面的内容,这里就不进行展示了,从上面的内容可以看出,如果想对一个对象应用AOP方式进行增强,首先需要为其定义对应的增强,同时为其描述对应的切点(上面没有明确指出是切点,所以默认是对所有的方法进行增强),以及对应的目标类,然后通过Spring的ProxyFactorybean来负责进行织入,产生对应的增强类。

不过,从上面的声明增强的方式中,我们也可以看出通过这种方式配置的缺点

  • 只能通过硬编码指定增强,并且需要为每个需要增强的类创建增强类
  • 无法明确指定切点,只能通过硬编码进行编写,且编写过程繁琐

由于通过这种方式的配置有着无法忍受的缺点,所以一般我们在实际开发过程中也没有这么做,至于一般怎么做,将在后面两个小节进行介绍

总结

由于面向对象编程本身存在着的不可避免的问题,于是提出了面向切面编程的概念,并且,随着前辈们的努力,AOP编程技术现在已经变得非常成熟了。在AOP中编程中,有几个比较重要的概念,切点,增强 ,引介,切面,织入,只有对这几个概念比较熟悉,才能更好地使用AOP技术来提高效率,在原始的Spring AOP技术中,如果需要声明一个增强,则需要实现对应的接口,这种方式是不太方便的,因为通过这种方式没有办法明确指定对应的切点,而且基本上必须为需要增强的对象编写对应的增强,在后面我们将看到,经过努力之后的Spring AOP配置方式的简便性。

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

推荐阅读更多精彩内容