死磕Spring AOP系列5:设计模式在AOP中的使用

死磕Spring AOP系列3:剖析Bean处理器之DefaultAdvisorAutoProxyCreator

死磕Spring AOP系列2:剖析Bean处理器之BeanNameAutoProxyCreator

死磕Spring AOP系列1:编程式实现AOP

死磕Spring AOP系列4:剖析AOP schema方式原理

通过前面的死磕,应该对AOP的原理都掌握了。annotation配置AOP,再没有讲的必要了。annotation和xml schema两种方式,仅仅是声明方式不同而已,其他的都一样。

Spring 作为一个流行的框架技术,它的代码设计是非常值得借鉴的。从编码风格到设计模式,有很多我们学习的点。本篇重点分析一下设计模式在AOP框架的使用,捎带着回顾下几个经典的设计模式。

使用设计模式,无外乎就是复用+解耦。引用鲁迅先生的一句话,“世间本没有模式,用的人多了,也便有了模式”。在学习模式的过程中,我经常学了忘,忘了学,费了不少劲,一直不得要领。最后,随着经验的积累,有了自己的一点认识。刚开始,我把重点放在类图,和角色的记忆,感觉挺简单的,感慨经过简单的组合搭配,实现系统解耦,可扩展性,对设计模式的作用有了认识,但这样学容易忘。慢慢的,我发现其实模式的学习,是场景与模式的匹配过程,需要我们去衡量,往往一个功能,有多个模式都能实现,这就要考验我们思维了。其实,往往很多优秀的框架技术,也会发生模式变化的,这都是一个道理。

主要内容包括

  1. 策略模式在AOP中的使用
  2. 模板模式在AOP中的使用
  3. 责任链模式在AOP中的使用
  4. 适配器模式在AOP中的使用
  5. 桥接模式在AOP中的使用

1策略模式在AOP的使用

1.1模式结构

  • Context: 环境类
  • Strategy: 抽象策略类
  • ConcreteStrategy: 具体策略类

1.2 spring中的使用

使用rose7画的图,接口实现的线有点问题。

策略模式的优点

  • 策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
  • 策略模式提供了管理相关的算法族的办法。
  • 策略模式提供了可以替换继承关系的办法。
  • 使用策略模式可以避免使用多重条件转移语句。

通过使用策略模式,比较容易灵活的实现了代理生成方式的替换。

简单看下环境类DefaultAopProxyFactory的代码片段

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
   if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
      Class targetClass = config.getTargetClass();
      if (targetClass == null) {
         throw new AopConfigException("TargetSource cannot determine target class: " +
               "Either an interface or a target is required for proxy creation.");
      }
      if (targetClass.isInterface()) {
         return new JdkDynamicAopProxy(config);
      }
      return CglibProxyFactory.createCglibProxy(config);
   }
   else {
      return new JdkDynamicAopProxy(config);
   }
}

1.3总结

  • 在策略模式中定义了一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式。策略模式是一种对象行为型模式。
  • 策略模式包含三个角色:环境类在解决某个问题时可以采用多种策略,在环境类中维护一个对抽象策略类的引用实例;抽象策略类为所支持的算法声明了抽象方法,是所有策略类的父类;具体策略类实现了在抽象策略类中定义的算法。
  • 策略模式是对算法的封装,它把算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法封装到一系列的策略类里面,作为一个抽象策略类的子类。
  • 策略模式主要优点在于对“开闭原则”的完美支持,在不修改原有系统的基础上可以更换算法或者增加新的算法,它很好地管理算法族,提高了代码的复用
    性,是一种替换继承,避免多重条件转移语句的实现方式;其缺点在于客户端必须知道所有的策略类,并理解其区别,同时在一定程度上增加了系统中类的个数,可
    能会存在很多策略类。
  • 策略模式适用情况包括:在一个系统里面有许多类,它们之间的区别仅在于它们的行为,使用策略模式可以动态地让一个对象在许多行为中选择一种行为;
    一个系统需要动态地在几种算法中选择一种;避免使用难以维护的多重条件选择语句;希望在具体策略类中封装算法和与相关的数据结构。

2.模板模式在AOP中的使用


    2.1 模板方法模式

  • 设计原则
         :破坏里氏替换,体现功能复用
  • 常用场景
         :一批子类的功能有可提取的公共算法骨架
  • 使用概率
         :80%
  • 复杂度
         :中低
  • 变化点
         :算法骨架内各个步骤的具体实现
  • 选择关键点
         :算法骨架是否牢固
  • 逆鳞
         :无

角色

抽象类(AbstractClass):实现了模板方法,定义了算法的骨架。

具体类(ConcreteClass):实现抽象类中的抽象方法,已完成完整的算法。

2.2模式总结
优点
  模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码。
   子类实现算法的某些细节,有助于算法的扩展。
   通过一个父类调用子类实现的操作,通过子类扩展增加新的行为,符合“开放-封闭原则”。
缺点
  每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计更加抽象。
适用场景
  在某些类的算法中,用了相同的方法,造成代码的重复。
  控制子类扩展,子类必须遵守算法规则。

2.3在spring中的使用

AOP相关的代理BeanPostProcessor。子类实现分别提供Annotation,schema等,实现模板是AbstractAutoProxyCreator.getAdvicesAndAdvisorsForBea和AbstractAdvisorAutoProxyCreator.findEligibleAdvisor 等处地方。

以AbstractAdvisorAutoProxyCreator.findEligibleAdvisor代码为例

protected List<Advisor> findEligibleAdvisors(Class beanClass, String beanName) {
   List<Advisor> candidateAdvisors = findCandidateAdvisors();
   List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
   extendAdvisors(eligibleAdvisors);//子类可以覆盖
   if (!eligibleAdvisors.isEmpty()) {
      eligibleAdvisors = sortAdvisors(eligibleAdvisors);//子类可以覆盖
   }
   return eligibleAdvisors;
}

经过分析代码,模板模式在AbstractAutoProxyCreator结构树中的使用有多处地方使用了模板模式。

3.责任链模式在AOP中的使用

3.1 职责链模式结构

设计原则 :遵循迪米特
    常用场景 :一个请求的处理需要多个对象当中的一个或几个协作处理
    使用概率 :15%
    复杂度 :中
    变化点 :处理链的长度与次序
    选择关键点 :对于每一次请求是否每个处理的对象都需要一次处理机会
    逆鳞 :无

  抽象处理者(Handler)角色:定义出一个处理请求的接口。如果需要,接口可以定义 出一个方法以设定和返回对下家的引用。这个角色通常由一个Java抽象类或者Java接口实现。上图中Handler类的聚合关系给出了具体子类对下家的引用,抽象方法handleRequest()规范了子类处理请求的操作。

 具体处理者(ConcreteHandler)角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。
优点:实现了请求者与处理者代码分离

缺点:了解处理流程困难

3.2 在AOP中的使用

其实,说这个不是责任链模式,也说得过去。因为这些Handler角色之间没有关系,他们之间的顺序是通过List管理的,也不太符合Handler"要么处理要么转发"这个特点。但,从使用者角度出发,这确实是个不折不扣的责任链模式。

4.适配器模式在AOP中的使用

4.1适配器模式结构

对象适配器:

类适配器

适配器模式包含如下角色:

  • Target:目标抽象类
  • Adapter:适配器类
  • Adaptee:适配者类
  • Client:客户类

适配器模式优点
    将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
    增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。
    灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。

类适配器模式还具有如下优点:
    由于适配器类是适配者类的子类,因此可以在适配器类中置换一些适配者的方法,使得适配器的灵活性更强。
对象适配器模式还具有如下优点:
    一个对象适配器可以把多个不同的适配者适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。

4.2适配器模式在Spring中的使用

这张图里还有另外一个模式。只需要关注MethodBeforeAdviceAdapter->MethodBeforeAdviceInterceptor-->MethodBeforeAdvice即可。

5.桥接模式在AOP中的使用

5.1模式结构

桥接模式包含如下角色:

  • Abstraction:抽象类
  • RefinedAbstraction:扩充抽象类
  • Implementor:实现类接口
  • ConcreteImplementor:具体实现类

桥接模式的优点:

分离抽象接口及其实现部分。
    桥接模式有时类似于多继承方案,但是多继承方案违背了类的单一职责原则(即一个类只有一个变化的原因),复用性比较差,而且多继承结构中类的个数非常庞大,桥接模式是比多继承方案更好的解决方法。
    桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统。
    实现细节对客户透明,可以对用户隐藏实现细节。
5.2桥接模式在Spring中的使用

严格来说,RefinedAbstraction有一个,这个设计图中基本每个Advisor都有对应的PointCut,和桥接模的设计这一点差别很大。还是那句话,从使用者角度来说,这应该也算桥接模式的一个范例。

总之,其实模式的落地应用与理论上,多多少少会存在出入。在不断深入了解过程中,慢慢补充吧。

参照:

http://www.tuicool.com/articles/BRZb2u

http://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/strategy.html

时间: 2024-10-01 23:33:09

死磕Spring AOP系列5:设计模式在AOP中的使用的相关文章

【死磕 Spring】----- IOC 之 获取验证模型

原文出自:http://cmsblogs.com 在上篇博客[死磕Spring]----- IOC 之 加载 Bean 中提到,在核心逻辑方法 doLoadBeanDefinitions()中主要是做三件事情. 调用 getValidationModeForResource() 获取 xml 文件的验证模式 调用 loadDocument() 根据 xml 文件获取相应的 Document 实例. 调用 registerBeanDefinitions() 注册 Bean 实例. 这篇博客主要分析

死磕Spring AOP系列4:剖析AOP schema方式原理

这个是<死磕Spring AOP系列>第4个.已经讲过的内容 死磕Spring AOP系列3:剖析Bean处理器之DefaultAdvisorAutoProxyCreator 死磕Spring AOP系列2:剖析Bean处理器之BeanNameAutoProxyCreator 死磕Spring AOP系列1:编程式实现AOP 通过前3篇,大家应该可以清楚的知道:AOP代理原理有3元素 BeanPostProcessor,作为代理对象初始入口 Advisor&Pointcut&M

死磕Spring AOP系列1:编程式实现AOP

作为[死磕Spring AOP]系列的第一篇, 这个系列是AOP源码分析级别的文章.由于现在AOP已经不是什么高深的技术,网上的例子也比比皆是,不论是xml schema,还是annotation声明式.相信用过Spring的朋友,都可以信手拈来. 本系列文章的原则 如何配置AOP不是重点 AOP相关概念讲解不是重点 AOP 底层代码设计才是重点 本篇的主要内容 认识ProxyFactory,并通过该工厂类,将"日志"和"安全校验"代码切入到业务逻辑中 分析代理对象

死磕Spring AOP系列2:剖析Bean处理器之BeanNameAutoProxyCreator

通过前一篇<死磕Spring AOP系列1:编程式实现AOP>,学习了Spring对代理的底层支持,认识了ProxyFactory对象,及从类设计层面认识了PointCut&Advisor&Advice&Interceptor,还认识了AdvisorChainFactory对象,知道了底层Advisor的底层链式结构.但是,上篇我们仅仅是通过Spring编程式实现的"AOP"效果,这种方式,实际开发时,如果这样用就太LOW了.今天,主要认识一个生成代

死磕Spring AOP系列3:剖析Bean处理器之DefaultAdvisorAutoProxyCreator

导航 死磕Spring AOP系列1:编程式实现AOP 死磕Spring AOP系列2:剖析Bean处理器之BeanNameAutoProxyCreator 这是<死磕Spring AOP系列>的第三篇.经过前面的讲解,已经掌握了以下知识点 Spring AOP的底层支持,是基于ProxyFactory+ProxyConfig+Advisor生成的 Spring容器的代理对象生成:在Bean生命周期过长中调用BeanPostProcessor,将对象进行包装,生成代理对象. Advisor的指

死磕Spring系列之一:准备阅读Spring源码环境

死磕Spring系列前言 死磕spring系列博客,是对Spring进行源码级阅读.工作以来,一直接触spring框架,可以说对spring框架的配置使用已经非常熟练了.个人感觉:Spring技术非常强大,简单的xml标签配置,就可以开启非常强大的支持功能,囊括J2EE企业应用的方方面面.使用归使用,但是却对spring底层设计和实现,一知半解."到底是什么优秀的设计,能让Spring无所不能,无所不包".最后,就有了我想研读Spring 源码的动力. 阅读任何任何一门框架源码,其实和

死磕 java同步系列之AQS终篇(面试)

问题 (1)AQS的定位? (2)AQS的重要组成部分? (3)AQS运用的设计模式? (4)AQS的总体流程? 简介 AQS的全称是AbstractQueuedSynchronizer,它的定位是为Java中几乎所有的锁和同步器提供一个基础框架. 在之前的章节中,我们一起学习了ReentrantLock.ReentrantReadWriteLock.Semaphore.CountDownLatch的源码,今天我们一起来对AQS做个总结. 状态变量state AQS中定义了一个状态变量state

死磕 java同步系列之redis分布式锁进化史

问题 (1)redis如何实现分布式锁? (2)redis分布式锁有哪些优点? (3)redis分布式锁有哪些缺点? (4)redis实现分布式锁有没有现成的轮子可以使用? 简介 Redis(全称:Remote Dictionary Server 远程字典服务)是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API. 本章我们将介绍如何基于redis实现分布式锁,并把其实现的进化史从头到尾讲明白,以便大家在面试的时候能讲清楚

死磕 java线程系列之线程池深入解析——未来任务执行流程

(手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本. 注:线程池源码部分如无特殊说明均指ThreadPoolExecutor类. 简介 前面我们一起学习了线程池中普通任务的执行流程,但其实线程池中还有一种任务,叫作未来任务(future task),使用它您可以获取任务执行的结果,它是怎么实现的呢? 建议学习本章前先去看看彤哥之前写的<死磕 java线程系列之自己动手写一个线程池(续)>,有助于理解本章的内容,且那边的代码比较短小,学起来相对容易一些. 问题