Spring dark horse: AOP notification type

Five 0. notice

Pre-notification : pointcut performed before performing the method;
post notice : the method is performed after the normal entry point for execution. It can only ever execute one exception notification;
exception notification : an entry point method is executed after the implementation of an exception. It and post a notice can only ever be executed;
final notice : No matter whether the normal entry point method to execute it will execute its back;

Around advice :4 contains written notification, the notification is generally the surroundBecause the results a bit different.

  • Spring framework provides us with an interface: ProceedingJoinPoint. The interface has a way to proceed (), this method is equivalent to explicitly call the entry point method.
  • The interface may be notified as a parameter surrounded, during program execution, spring framework provides the interface implementation class for us to use for us.
  • There pointcut surround notification method and the notification type 4, FIG.
    Here Insert Picture Description

1.bean.xml configuration

  • (1) In aop: pointcut expressions written (Public cut surface within pointcut label ), following various types of notifications can call this pointcut expression.
  • (2) in aop: write notification method and the notification type tag aspect , the top source of the write notification class.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--配置spring的IOC,把service对象配置进来-->
    <bean id="accountService" class="com.jh.service.impl.AccountServiceImpl"></bean>

    <!--配置Logger类-->
    <bean id="logger" class="com.jh.utils.Logger"></bean>

    <!--配置AOP-->
    <aop:config>
        <!-- 配置切入点简便表达式:id属性用于指定表达式的唯一标识。expression属性用于指定表达式内容
             此标签写在aop:aspect标签内部只能当前切面使用。
             它还可以写在aop:aspect外面,此时就变成了所有切面可用,必须写在前面(配置AOP的顺序)
         -->
        <aop:pointcut id="pt1" expression="execution(* com.jh.service.impl.*.*(..))"></aop:pointcut>
        <!--配置切面-->
        <aop:aspect id="logAdvice" ref="logger">
            <!--配置前置通知:在切入点方法执行之前执行-->
            <aop:before method="beforePrintLog" pointcut-ref="pt1"></aop:before>
            <!--配置后置通知:在切入点方法正常执行之后执行。它和异常通知永远只能执行一个-->
            <aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"></aop:after-returning>
            <!--配置异常通知:在切入点方法执行产生异常之后执行。它和后置通知永远只能执行一个-->
            <aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"></aop:after-throwing>
            <!--配置最终通知:无论切入点方法是否正常执行它都会在其后面执行-->
            <aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>
            <!-- 配置环绕通知 详细的注释请看Logger类中-->
           <aop:around method="aroundPrintLog" pointcut-ref="pt1"></aop:around>
        </aop:aspect>
    </aop:config>
</beans>

Figure:Here Insert Picture Description


2. XML configuration of each layer with respect to the change

service: Interface No change
service: implementation class

package com.jh.service.impl;
import com.jh.service.IAccountService;
/**
 * 账户的业务层实现类
 * */
public class AccountServiceImpl implements IAccountService {
    @Override
    public void saveAccount() {
        System.out.println("执行了保存");
        //int i=1/0;
        /**结果:
         * 前置通知Logger类中的beforePrintLog方法开始记录日志了。。。
         * 执行了保存
         * 异常通知Logger类中的afterThrowingPrintLog方法开始记录日志了。。。
         * 最终通知Logger类中的afterPrintLog方法开始记录日志了。。。
         * */
    }

    @Override
    public void updateAccount(int i) {
        System.out.println("执行了更新操作:"+i);
    }

    @Override
    public int deleteAccount() {
        System.out.println("执行了删除");
        return 0;
    }
}

When System.out.println ( "a save"); the presence of the following exception statement int i = 1/0; when the output statement normally.
Result :( abnormality notification and post-notification can not coexist )

前置通知Logger类中的beforePrintLog方法开始记录日志了。。。
执行了保存
异常通知Logger类中的afterThrowingPrintLog方法开始记录日志了。。。
最终通知Logger类中的afterPrintLog方法开始记录日志了。。。

utils: Logger class notice

 package com.jh.utils;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* 用于记录日志的工具类,它里面提供了公共的代码
* */
public class Logger {
  /**前置通知*/
  public  void beforePrintLog(){
      System.out.println("前置通知Logger类中的beforePrintLog方法开始记录日志了。。。");
  }

  /**后置通知*/
  public  void afterReturningPrintLog(){
      System.out.println("后置通知Logger类中的afterReturningPrintLog方法开始记录日志了。。。");
  }

  /**异常通知*/
  public  void afterThrowingPrintLog(){
      System.out.println("异常通知Logger类中的afterThrowingPrintLog方法开始记录日志了。。。");
  }

  /**最终通知*/
  public  void afterPrintLog(){
      System.out.println("最终通知Logger类中的afterPrintLog方法开始记录日志了。。。");
  }

  /**
   * 环绕通知
   * 问题:当我们配置了环绕通知之后,切入点方法没有执行,而通知方法执行了。
   * 分析:
   *通过对比动态代理中的环绕通知代码,发现动态代理的环绕通知有明确的切入点方法调用,而我们的代码中没有。
   * 解决:
   * Spring框架为我们提供了一个接口:ProceedingJoinPoint。该接口有一个方法proceed(),此方法就相当于明确调用切入点方法。
   *该接口可以作为环绕通知的方法参数,在程序执行时,spring框架会为我们提供该接口的实现类供我们使用。
   * spring中的环绕通知:
   *    它是spring框架为我们提供的一种可以在代码中手动控制增强方法何时执行的方式。
   * */
  public Object aroundPrintLog(ProceedingJoinPoint pjp){
      Object rtValue=null;
      try {
          Object[] args=pjp.getArgs();//得到方法执行所需的参数
          System.out.println("Logger类中的aroundPrintLog方法开始记录日志了。。。前置");
          rtValue=pjp.proceed(args);//明确调用业务层方法(切入点方法)
          System.out.println("Logger类中的aroundPrintLog方法开始记录日志了。。。后置");
          return rtValue;
      } catch (Throwable t) {
          System.out.println("Logger类中的aroundPrintLog方法开始记录日志了。。。异常");
         throw new RuntimeException(t);
      } finally {
          System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。最终");
      }
  }
}

Generally only result surround notify:

Method aroundPrintLog Logger class logging the start. . . Front
a save
aroundPrintLog method Logger class start logging a. . . Rear
aroundPringLog method Logger class logging the start. . . finally


Test class AOPTest

package com.jh.test;
import com.jh.service.IAccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**测试AOP的配置*/
public class AOPTest {
    public static void main(String[] args) {
        //1.获取容器
        ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");
        //2.根据id获取service bean对象
        IAccountService as=(IAccountService)ac.getBean("accountService");
        //3.执行方法
        as.saveAccount();
    }
}

Handwriting four results :( typically perform only 3, rear throwing advice not exist)

BeforePrintLog method for pre-notification Logger class start logging a. . .
A save
final notification afterPrintLog method Logger class start logging a. . .
The method of notification afterReturningPrintLog rear Logger class logging the start. . .

The results found with four different surround notice:
Around advice is the final notice in the end, it is generally used around advice.

Published 101 original articles · won praise 15 · views 6765

Guess you like

Origin blog.csdn.net/JH39456194/article/details/104435238