美文网首页
Spring 与 AOP(第三讲)

Spring 与 AOP(第三讲)

作者: 辽A丶孙悟空 | 来源:发表于2020-08-02 19:02 被阅读0次
通知 Advice

通知(Advice), 切面的一种实现, 可以完成简单织入功能(织入功能就是在这里完成的)。常用通知有:前置通知、后置通知、环绕通知、异常处理通知。

  • 通知的使用步骤
    对于通知的定义、配置与使用,主要分为以下几步:
    (1)定义目标类
    定义目标类,就是定义之前的普通 Bean 类,也就是即将被增强的 Bean 类。
    (2)定义通知类
    通知类是指,实现了相应通知类型接口的类。当前,实现了这些接口,就要实现这些接口中的方法,而这些方法的执行,则是根据不同类型的通知,其执行时机不同。
    前置通知:在目标方法执行之前执行。
    后置通知:在目标方法执行之后执行。
    环绕通知:在目标方法执行之前与之后均执行。
    异常处理通知:在目标方法执行过程中,若发生指定异常,则执行通知中的方法一。
    (3)注册目标类
    即在 Spring 配置文件中注册目标对象 Bean。

    (4)注册通知切面
    即在 Spring 配置文件中注册定义的通知对象 Bean。

    (5)注册代理工厂 Bean 类对象 ProxyFactoryBean

    这里的代理使用的是 ProxyFactoryBean 类。代理对象的配置,是与 JDK 的 Proxy 代理参数是一致的,都需要指定三部分:目标类,接口,切面。
    <property name="target" ref="目标对象 Bean 的 id " />
    指定目标对象的 Bean 的 id。也可写为如下形式:
    <property name="targetName”value="目标对象 Bean 的 id " />
    <property name="proxyInterfaces" value="接口全限定性名" />
    设置目标对象所实现的业务接口,要求给出接口的全既定性类名。此属性可以不进行设置,因为打开 ProxyFactoryBean 的源码,可以看到其有个自动检测目标类的所有接口属性 autodetectInterfaces,默认值为 true。即不设置也可以自动检测到。当然,此时使用的是 jdk 的 Proxy 动态代理。

    如果目标对象没有实现业务接口,则可以不设置。此时使用的是 CGLIB 动态代理。
    <property name-="interceptorNames" value=“通知的id" />
    指定切面,这里指通知。注意,这里对于 id 的指定使用的是 value 属性,而非 ref。因为该属性名为 xxNames,是名称,所以其值为字符串,而非对象。
    (6)客户端访问动态代理对象
    客户端访问的是动态代理对象,而非原目标对象。因为代理对象可以将交叉业务逻辑按照通知类型,动态的织入到目标对象的执行中。

    (7)在容器中的整体配置
  • 通知详解
    (1)前置通知(MethodBeforeAdvice)
    定义前置通知,需要实现 MethodBeforeAdvice 接口。该接口中有一个方法before(), 会在目标方法执行之前执行。前置通知的特点:
    ① 在目标方法执行之前先执行。
    ② 不改变目标方法的执行流程,前置通知代码不能阻止目标方法执行。
    ③ 不改变目标方法执行的结果。
    举例:aop01_01 包。
    定义业务接口与目标类,


    定义前置通知:

    配置文件配置:

    对于测试类,需要注意,从容器中获取的事代理对象,而非目标对象。

    查看后台运行情况,可以看到代理生成使用的是 JDK 代理机制。

    (2)后置通知 AfterReturningAdvice
    定义后置通知,需要实现接口 AfterReturningAdvice 该接口中有一个方法afterReturning(),会在目标方法执行之后执行。后置通知的特点:
    ① 在目标方法执行之后执行。
    ② 不改变目标方法的执行流程后置通知代码不能阻止目标方法执行。
    ③ 不改变 目标方法执行的结果。
    举例:aop01_02 包。
    修改业务接口与实现类:


    定义切面:通知

    配置文件配置:

    (3)环绕通知 MethodInterceptor
    定义环绕通知,需要实现 MethodInterceptor 接口。环绕通知,也叫方法拦截器,可以在目标方法调用之前及之后做处理,可以改变目标方法的返回值,也可以改变程序执行流程。注意,org.aopalliance.intercept.MethodInterceptor 才是需要的包。
    举例:aop01_03 包。



    (4)异常通知 ThrowsAdvice
    定义异常通知,需要实现 ThrowsAdvice 接口。该接口的主要作用是,在目标方法抛出异常后,根据异常的不同做出相应的处理。当该接口处理完异常后,会简单地将异常再次抛出给目标方法。
    不过,这个接口较为特殊,从形式上看,该接口中没有必须要实现的方法。但,这个接口却确实有必须要实现的方法 afterThrowing()。这个方法重载了四种形式。由于使用时,一般只使用其中一种,若要都定义到接口中,则势必要使程序员在使用时必须要实现这四个方法。这是很麻烦的。所以就将该接口定义为了标识接口(没有方法的接口)。
    这四个方法在打开 ThrowsAdvice 源码后,上侧的注释部分可以看到:

    不过,在这四种形式中,常用的形式如下:
    public void afterThrowing(自定义的异常类e)
    这里的参数 e 为,与具体业务相关的用户自定义的异常类对象。容器会根据异常类型的不同,自动选择不同的该方法执行。这些方法的执行是在目标方法执行结束后执行的。
    其它参数则与前面两个通知中方法的参数意义相同。
    举例:aop01_04 包。
    本例实现用户身份验证。当用户名不正确时,抛出用户名有误异常;当密码不正确时,抛出密码有误异常。当然,在抛出这些异常后,都要做一些其它处理。
    Step1:定义异常类的父类。

    Step2:定义两个异常类的子类。


    Step3:定义业务接口类。要抛出异常父类。

    Step4:定义目标类。

    Step5:定义异常通知。

    Step6:配置文件配置。

    Step7:定义测试类。
  • 通知的其他方法
    (1)给目标方法织入多个切面
    若要给目标方法织入多个切面,则需要在配置代理对象的切面属性时,设定为 list。
    举例: aop01_05 包。
    将前置通知与后置通知拷贝到同一个项目中。



    (2)无接口的 CGLIB 代理生成
    若不存在接口,则 ProxyFactoryBean 会自动采用 CGLIB 方式生成动态代理。
    举例: aop01_06 包。



    查看后台运行情况,可以看到代理生成使用的是 CGLIB 代理机制。

    (3)有接口的 CGLIB 代理生成 proxyTargetClass 属性
    若存在接口,但又需要使用 CGLIB 生成代理对象,此时,只需要在配置文件中增加一个 proxyTargetClass 属性设置,用于指定强制使用 CGLIB 代理机制。
    举例: aop01_07 包。

    也可指定 optimize (优化)的值为 true ,强制使用 CGLIB 代理机制。



    查看后台运行情况,可以看到代理生成使用的是 CGLIB 代理机制。

相关文章

网友评论

      本文标题:Spring 与 AOP(第三讲)

      本文链接:https://www.haomeiwen.com/subject/uazlrktx.html