zoukankan      html  css  js  c++  java
  • spring aop

    annotation配置AOP,再没有讲的必要了。annotation和xml schema两种方式,仅仅是声明方式不同而已,其他的都一样。

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

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

    主要内容包括

    1. 策略模式在AOP中的使用

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

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

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

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

    1策略模式在AOP的使用

    1.1模式结构

    Strategy.jpg

    • Context: 环境类

    • Strategy: 抽象策略类

    • ConcreteStrategy: 具体策略类

    1.2 spring中的使用

    wKioL1dTnKKCDewWAAA4czN6c5I498.png

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

    策略模式的优点

    • 策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。

    • 策略模式提供了管理相关的算法族的办法。

    • 策略模式提供了可以替换继承关系的办法。

    • 使用策略模式可以避免使用多重条件转移语句。

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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%

    • 复杂度      :中低

    • 变化点      :算法骨架内各个步骤的具体实现

    • 选择关键点      :算法骨架是否牢固

    • 逆鳞      :无

    2012070917340125.png

    角色

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

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

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

    2.3在spring中的使用

    wKiom1dTp8HwVNiFAABiKqgjRf0437.png

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

    以AbstractAdvisorAutoProxyCreator.findEligibleAdvisor代码为例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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)角色:具体处理者接到请求后,java培训可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。
    优点:实现了请求者与处理者代码分离

    缺点:了解处理流程困难

    3.2 在AOP中的使用

    wKiom1dTs-agdTY7AABepZy779A983.png

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

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

    4.1适配器模式结构

    对象适配器:

    Adapter.jpg

    类适配器

    Adapter_classModel.jpg

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

    • Target:目标抽象类

    • Adapter:适配器类

    • Adaptee:适配者类

    • Client:客户类

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

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

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

    wKiom1dTvJTgKzu5AABi2G7apbw010.png

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

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

    5.1模式结构

    Bridge.jpg

    桥接模式包含如下角色:

    • Abstraction:抽象类

    • RefinedAbstraction:扩充抽象类

    • Implementor:实现类接口

    • ConcreteImplementor:具体实现类

    桥接模式的优点:

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

    wKiom1dTyHqgqRVLAABFkG--KZ0173.png

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

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

  • 相关阅读:
    使用socket BPF/Linux内核工程导论——网络:Filter(LSF、BPF、eBPF)
    使用Iperf工具测试android系统网络wifi的吞吐量wifithrougput
    html input中 button和submit的区别
    Linux转发性能评估与优化(转发瓶颈分析与解决方案)
    交叉编译器 arm-linux-gnueabi 和 arm-linux-gnueabihf 的区别
    MySQL查询不区分大小写的sql写法
    Docker镜像保存save、加载load
    将Spring-boot应用部署到Docker容器
    Docker 安装使用
    Scalatra文件下载时中文乱码
  • 原文地址:https://www.cnblogs.com/plan123/p/5562820.html
Copyright © 2011-2022 走看看