关于SpringAOP的理解

  1. 第一次听说DI、IOC、AOP还是在自学javaSE末尾那段时光,老是看到网上的面试视频,特别是八股文相关的视频;说实话当时并不知道java的前路还有这么多的知识,那个时候不知道什么Spring,SpringMVC,还有什么微服务这些;但是由于提前看到了,造成了莫名的迷茫和压力,所以还是顶着难受开始直接去尝试学习这些框架,我相信有很多人会是跟我一样的做法;我们不去谈这样的学习流程是否正确,中间的确是缺少了很多的前提知识,但我认为学习框架如果只是会使用的话其实是非常快速的尽管很难受(有太多疑问),但是要理解一个框架的核心技术是非常困难的,其实不同的底蕴的人会有不同的理解深度,你可能认为深度理解又怎么样呢还不是一样的使用!其实差别还是非常大的,我一直追捧技术在于创造,而不是搬运,虽然我平时大部分时间也在copy别人的想法和代码,但我对此一直不满,奈何能力有限。

  2. 言归正传,我们继续聊聊AOP或者说SpringAOP;作为Spring框架的核心模块,它蕴含了非常深刻的设计思想,首先spring本身是号称为了简化java开发,主要是提供一个充分解耦的编程框架,那么充分解耦这个词非常关键,它从小到一个类成员、类的方法到类与类之间,业务与业务之间大到服务与服务之间的设计都实现了合理的解耦合,我们知道这与反射技术的运用是分不开的,反射是框架的基础,它与我们熟知的工厂模式结合读取XML文件一起实现了我们的控制反转和依赖注入,使得我们不用显示的去使用new构造一个对象造成关联的耦合。就像类似于下面这样的操作原理一样。

  3. Properties p=new Properties(); //通过获取本类对象的类加载器的获取路径输入流,得到配置文件的输入流 InputStream input=CoffeeFactory.class.getClassLoader().getResourceAsStream("bean.properties"); try { p.load(input); //从p中获取全类名,通过返回的键的set集合, 获取值(全类名),创建对象 Set<Object> keys=p.keySet(); for(Object key:keys){ String className=p.getProperty((String) key); //通过反射,调用字节码对象的无参构造创建对象(Object类型) Class clazz=Class.forName(className); Coffee coffee=(Coffee)clazz.newInstance(); //存储 map.put((String)key,coffee); } } catch (Exception e) { e.printStackTrace(); }

  4. 而后基于此我们再往后去看AOP,它又是依赖于那些技术实现了那些功能呢?刚开始时学习AOP时,我老是吧代理知识和AOP混在一起傻傻分不清楚;那时其实对于AOP并没有什么深刻的认识,AOP只是具有指导意义的思想和设计理念,实现方法其实有很多种。我们先不去关注这几种具体的主流实现方式,单从AOP本身这个概念来看看,弄清楚它的提出是为什么,如何理解它的组成部分显然是更为关键的。

  5. 我想,如果你事先了解过设计模式的设计原则的话,也许会深有感触,为了保证程序之间互不影响又能在尽量少的耦合度下完成基本功能,我们谈到对于程序的设计应该保证单一职责法则,开闭原则,合成复用原则等原则;保证一个对象具有单一的功能职责,不包含多余的其他功能,同时对外保持开放方便扩展,对内修改保持封闭避免连带影响,还要满足复用的能力,这非常重要,没有复用的功能程序不是一个好程序。
    6 . 那么实际情况是,在我们的项目中有很多地方,我们有一些需要重复处理的工作夹杂在各个模块的各个功能代码中;这些重复的与原先功能代码无关的代码,如果放到功能对象中去处理,就会破坏我们美丽的设计,不仅仅使得程序显得臃肿复杂还增加了程序的耦合度,破坏程序的健壮性。这些操作有很多,比如我们的日志操作、缓存记录、安全相关处理和事务相关的管理操作的代码等等,他们都需要插入到具体某个功能对象中执行他们的预处理或者事后处理操作。
    尽管很多地方对于AOP的作用解释是用于将业务逻辑代码和非业务逻辑代码进行解耦分离,但是我认为这也许有些片面,尽管大部分时间来看,在开发中它的确是做这样一件事情,但我还是倾向于从单一职责和合成复用原则上来解释它。
    这里我列举Craig walls的《Spring实战第三版》中的电表员监控用电量案例:今年夏天天气格外的热,每家每户都需要开空调;很明显开空调会花费很多的电量,那么电力公司就需要为每家每户安装电表来记录用户的用电量,并且安排抄表员去抄表将数据汇报给电力公司。作为一个程序员我们先拆解一下这个故事中出现了几个对象:
    在这里插入图片描述

    上图中的对象有:用户,电表,抄表员三个,而其中又有三个功能:开空调、记录用电、监控用电;我们知道用户应该只负责打开空调,而从逻辑上讲我们不可能让用户自己去监控用电量然后上报给电力公司吧(公司得亏成什么样子!)。但是只要空调运转起来,这个过程就必然需要记录用电量的,而监控用电量就自然交给抄表员去做会更好,用户只需要开空调享受,这样我们就将各自的职责清晰了起来,且职责上互不影响。但是我们不要忘了,尽管职责不影响,但是在完成开空调整个事件上他们是需要交集的,如果去使用继承或者委托显然是很那个的想法,所以还是要利用DI配置,让容器去负责对象的构建和销毁,我们只负责声明。
    面向对象,面向对象,在Java中切面也是难以逃脱这个理念的,所以切面的组成原子肯定是个对象,这一点我们要先了解。
    切面的设计概念大致就是,我们定义好了通用的功能(例如:监控用电或者抄表员本身)而且使用声明的方式去控制这个功能以什么方式在什么地方去执行,而不需要去修改执行的那个地方的代码,可以理解为一个装饰哪里需要哪里搬(又有点装饰者模式那味儿了);那么具体它如何实现这个控制呢?我们再继续看切面的组成部分:
    (1)通知:直观上讲,它是切面也就是上面监控用电这个功能或者说抄表员这个对象里面的成员,是个标准的java类,抄表员要完成监控用电这个功能,就必须要去完成三件事情:先获取用户名单、去抄电表、之后再去公司汇报数据,三件事情在对象中表现为三个方法或者功能对象,即通知,他们有目标方法被调用之前,调用之后,执行之后,异常之时,或者调用前后这几个时间点去控制切面任务的执行。
    (2)连接点:很明显的一件事情是抄表员是要去指定用户家里面去抄表的,目标用户类自然就是切面的连接点。
    (3)切点:在目标用户中,显然不止有空调、电表这些成员,还有花园、汽车等等,切点的作用是为了进一步确认抄表员要针对的对象,这里肯定是针对电表的记录电表这个方法,那么电表就是具体在目标类中的切点。
    以上就是我们切面的组成部分,接下来我们在谈一下,切面的运行方式,也就是如何切
    (1)引入方式:引入是可以向现有的类里面添加新的方法或者属性的,这意味着他可以将我们定义好的通知类对象引入到目标类中去执行一下,而不需要修改目标类的代码逻辑。
    (2)织入方式:为什么一开始老是将代理和AOP的概念混在一起,其实就是因为织入这个“搅屎棍”;它只是我们运行切面的一种较为巧妙的方式,目的是为了实现业务逻辑的解耦;这个方式确实是运用了代理模式来实现。利用反射通过获取委托类的构造方法在运行期创建代理对象运用增强invoke去完成切面任务。代理的增强方法与【切面相对于目标类要执行的多余方法】概念上的确类似,这导致了一开始我的错觉,认为代理就是AOP;其实织入的时机也有多个,可以说编译期、类加载期、还有就是我们常用的运行期,这是因为SprigAOP选择。
    本章我们主要关注与SpringAOP对AOP的实现,所以我们首先要了解在Spring框架当中AOP有哪些特点:
    1.首先是通知的定义,在spring中的通知都是使用标准的java类;这意味着我们java开发人员可以熟悉的使用XML方式去实现控制反转和DI。
    2.对于切面的切面方式。spring采用在运行期调用通知对象将切面以织入的方式添加到容器管理的目标bean中;这显然很方便,因为bean容器本身就是反射的运用。代理类生成时已经包含了目标类的功能,它会拦截通知作用到的那个具体目标功能,执行切面逻辑并将目标方法的调用转发到目标类中去执行。
    在这里插入图片描述
    3.spring只支持方法连接点,由于代理的方式是采用动态代理,jdk或者说JDK API的接口代理,所以它注定是支持方法为连接点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑色帽子的蓝鲸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值