• 框架——切面框架——aop——集成Spring


    本篇介绍aspect ----> spring aop的兼容性,以及spring aop额外提供的功能。

    它有两种形式,

    第一种形式配合注解语法,普通bean,开启代理。

    第二种语法纯xml方式,使用aop:config以及子标签。

    额外功能:

    spring aop提供了更简便使用load time weave的方式。只需要在任意的spring配置文件中添加<context:load-time-weaver>即可。

    1、代理方式

    步骤如下:

    第一步,编写任意的HelloService以及实现类,由于spring aop使用JDK代理实现,所以必须是接口。略。

    第二步,编写任意的HelloAspect, 注解语法。略。

    第三步,在任意的spring配置文件中添加如下信息:

    <!-- HelloService类 -->
    <bean id="helloService" class="learn.springcore.aop.HelloServiceImpl"/>
    <!-- 定义aspect -->
    <bean id="helloAspect" class="learn.springcore.aop.HelloAspect"/>
    <!-- 开启aspect代理 -->
    <aop:aspectj-autoproxy/>
    

      第四步,验证,通过applicationContext获取bean,调用HelloService中的方法。

    1.1    原理

    上述示例中,核心配置是aspectj-autoproxy,它会创建代理对象。它默认使用的是JDK代理。设置proxy-target-class属性为true,切换为CGlib方式。

    它会使spring进行以下四个步骤:

    1. 首先检查当前bean是否是aspect,依据是类上是否有@Aspect注解
    2. 其次检查当前bean是否被选取,依据是pointcut的语法规则。
    3. 若bean被选取,自动创建bean的代理对象proxy,代理对象与bean实现相同的接口。若使用CGLIB,代理对象会继承bean。
    4. 当获取bean时,返回创建的代理对象proxy。

    上述方式的缺陷是:

    由于是代理方式,所以必须是接口,所以join point类型只能是call,其他类型均不支持。

    aspect与join point选择的Java类必须都是已注入到spring 容器中的bean。

      运行target的方法时,内部调用的方法都无法再作为join point,无法被选择。代理时只适用于该方法,例如target有test方法,它内部调用hello方法,代理只适用于test方法,其内部的方法不再通过代理对象,即在test方法内部调用hello方法,不会再经过代理对象。

    1.2   兼容性

    1.2.1   aspect

    对于association,只支持isSingleton,perthis, pertarget。其他均不支持。

    优先级不再使用@DeclarePrecedence,而是实现Order接口,值越小,优先级越高。

    privileged关键字和特殊方法在xml中均不适用。

    1.2.2   pointcut

    只支持execution类型的join point,其他均不支持。

    收集上下文时,只支持target(), this(), args(), within(), @target, @this, @args, @within,其他均不支持。

    spring aop额外提供的bean()语法选择容器中的bean。

    bean(标识): 根据bean的id,name,alias选取。

    bean(*Controller || *Service || *Repository):根据bean的类型,由于类型通常在类名上体现,例如Controller通常都以Controller为后缀,所以也可以理解为根据类的名称。

    bean(urlPattern):bean的类型为Controller,根据urlPattern选择Controller。

    bean(prefix/*/suffix):bean的标识或类名以prefix为前缀,suffix为后缀。

    1.2.3   advice

    advice语法全部支持。

    唯一区别在around类型的advice中运行proceed方法。

    注解语法是不需要传递任何参数的,即proceed会运行join point选择的方法。参数是自动传递的。

    spring aop方式下需要将参数传入proceed方法中,默认会获取this, target收集到的参数。可以调用ProceedJoinPoint的getArgs方法,方法的返回值为Object[]。并运行proceed(object[])。

    2、XML 

    <!-- XML注解方式使用Aspect -->
    <aop:config proxy-target-class="false">
    	<!-- 定义全局的pointcut -->
    	<aop:pointcut expression="" id=""/>
    	<!-- 定义aspect -->
    	<aop:aspect ref="aspect bean" order="1">
    		<!-- 定义只使用当前advice的aspect -->
    		<aop:pointcut expression="" id=""/>
    		<!-- 定义before advice -->
    		<aop:before pointcut-ref="" method=""/>
    	</aop:aspect>
    </aop:config>
    

    2.1  aspect标签

    由一组pointcut, advice组成。

    ref表示aspect的bean ID, order定义aspect的优先级,实现Order接口,值越小,优先级越高

    2.1.1   pointcut标签

    id用于指定pointcut的标识,方便advice引用。

    expression指定pointcut表达式,只支持execution类型的Pointcut,收集上下文的方式有限,参考pointcut兼容性。

    在aspect之外定义的pointcut为作用域为全局的,aspect之内定义的只适用于当前aspect。

    2.1.2   advice标签

    全部类型都支持。

    pointcut-ref引用已定义的pointcut。

    pointcut属性直接定义pointcut表达式。

    method,advice对应的Java方法名称,等价于注解方式下在方法上添加@Advice相关注解。

    arg-names:对应@Before注解中的argName属性,用于收集上下文。

    returning属性只适用于after-returning,收集的方法返回值。

    throwing属性只适用于after-throwing,收集的异常类型。

    2.1.3  declare parents标签

      只适用于接口,并提供默认的接口实现类。它的配置如下:

    <!-- 定义aspect -->
    <aop:aspect order="2">
    	<!-- 定义declare parents -->
    	<aop:declare-parents types-matching="" implement-interface="" default-impl=""/>
    </aop:aspect>
    

      传统的aspect语法格式为:declare parents : “类签名” implements XXInterface

      它们之间的映射关系为:

    1. declare-parents对应declare parents关键字。
    2. type-matching:对应类签名。
    3. implement-interface:对应接口。
    4. default-impl:接口的默认实现类,无对应值,在传统Aspect使用static aspect impl语法添加接口的默认实现。

    3、load time

    Spring简化了load time weaving的使用,默认情况下需要在虚拟机中添加agent选项。spring只需要配置<context:load-time-weaver>。

    4、对比

    通常不使用xml方式,即配置aop-config,是因为其只支持execution,许多功能都不支持。

    建议使用注解语法,并配合spring的load time,最简单的一种方式。

    注解语法支持了传统语法的大部分功能,若要实现其他功能,选择传统语法,传统语法的功能是最强大的。

  • 相关阅读:
    JDBC批量删除某一用户下的触发器
    DWZ框架修改默认主页(转)
    JSP页面中的js方法遍历后台传来的自定义对象的List
    JDBC获取表注释
    你的显示方式安全么?JSTL中c:out标签介绍
    tomcat启动报错
    PPP协议体系的实现
    Linux下的虚拟Bridge实现
    三皇五帝
    贴近原理层的科技发展
  • 原文地址:https://www.cnblogs.com/rain144576/p/14708691.html
Copyright © 2020-2023  润新知