Spring AOP 通知

AOP:面向切面编程(也叫面向方面编程):Aspect Oriented Programming(AOP),是软件开发中的一个热点,也是 Spring框架中的一个重要内容。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等

下面总结下AOP几种通知(切入方式)。
首先:
建立操作的接口ActionService:

public interface ActionService {
    public void addAction(String param);
}

ActionService的实现类:ActionServiceImpl

public class ActionServiceImpl implements ActionService{
    @Override
    public void addAction(String name) {
        System.out.println("执行参数:"+name+"===执行动作进行中......");
    }
}

再建立一个切面类:ActionServiceAspect,该类主要是承载各种切入(通知)情况

public class ActionServiceAspect {
 .......
 通知代码
 .......
}

applicationContext.xml

<?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">

    <bean id="actionServiceAspect" class="com.java.advice.ActionServiceAspect"></bean>

    <bean id="actionService" class="com.java.service.impl.ActionServiceImpl"></bean>

    <!-- AOP配置 -->
    <aop:config>
        <!-- 配置一个切面 -->
        <aop:aspect id="actionServiceAspect" ref="actionServiceAspect">
            <!-- 定义个切点: expression方法表达式-->
            <aop:pointcut expression="execution( * com.java.service.*.*(..))" id="pointCut"/>        
           <!-- 以下配置通知 -->
             ......
             ......
        </aop:aspect>

    </aop:config>

</beans>

建测试类Test.java 执行测试结果:

public static void main(String[] args) {
        ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
        //这里使用到多态,可以指向具体的实现类
        ActionService sService=(ActionService)ac.getBean("actionService");
        sService.addAction("ActionParam");
    }

1、前置通知
在ActionServiceAspect.java中加入前置的方法

public void doBefore(JoinPoint jp){
        System.out.println("前置通知");
        System.out.println("操作的类名:"+jp.getTarget().getClass().getName()); 
        System.out.println("操作的方法名:"+jp.getSignature().getName()); 
        System.out.println("执行方法的参数:"+jp.getArgs()[0]); 
    }

applicationContext.xml在AOP中配置前置通知

   <!-- AOP配置 -->
    <aop:config>
        <!-- 配置一个切面 -->
        <aop:aspect id="actionServiceAspect" ref="actionServiceAspect">
            <!-- 定义个切点: expression方法表达式-->
            <aop:pointcut expression="execution( * com.java.service.*.*(..))" id="pointCut"/>
            <!-- 前置通知 -->
            <aop:before method="doBefore" pointcut-ref="pointCut"/>
        </aop:aspect>
    </aop:config>

执行Test.java,结果:

(前置通知)
操作的类名:com.java.service.impl.ActionServiceImpl
操作的方法名:addAction
执行方法的参数::ActionParam
执行参数:ActionParam===执行动作进行中......

顾名思义,前置通知,切入方法执行前执行。

2.后置通知
在ActionServiceAspect.java中加入后置通知的方法

public void doBeAfter(JoinPoint jp){
        System.out.println("执行动作完成(后置通知)");
    }

applicationContext.xml在AOP中配置后置通知

  <!-- AOP配置 -->
    <aop:config>
        <!-- 配置一个切面 -->
        <aop:aspect id="actionServiceAspect" ref="actionServiceAspect">
            <!-- 定义个切点: expression方法表达式-->
            <aop:pointcut expression="execution( * com.java.service.*.*(..))" id="pointCut"/>
            <!-- 后置通知 -->
            <aop:after method="doBeAfter" pointcut-ref="pointCut"/>
        </aop:aspect>
    </aop:config>

Test.java执行结果(切入操作方法完成后再执行):

执行参数:ActionParam===执行动作进行中......
执行动作完成(后置通知)

3.环绕通知
在ActionServiceAspect.java中加入环绕通知的方法

    public Object doAround(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("执行动作前(环绕通知)..........");
        //pjp.proceed()相当调用addAction方法,返回值相当于方法的返回值
        Object obj=pjp.proceed();
        System.out.println("执行动作后(环绕通知)..........");
        return obj;
    }

applicationContext.xml在AOP中配置环绕通知

 <!-- AOP配置 -->
    <aop:config>
        <!-- 配置一个切面 -->
        <aop:aspect id="actionServiceAspect" ref="actionServiceAspect">
            <!-- 定义个切点: expression方法表达式-->
            <aop:pointcut expression="execution( * com.java.service.*.*(..))" id="pointCut"/>
             <!-- 配置环绕通知 -->
            <aop:around method="doAround" pointcut-ref="pointCut"/>
        </aop:aspect>
    </aop:config>

执行结果:

执行动作前(环绕通知)..........
执行参数:ActionParam===执行动作进行中......
执行动作后(环绕通知)..........

由此可见,环绕通知囊括前置、后置通知,所以使用环绕通知就不必要使用前后置,当然,视需求而定。

4.返回通知
在ActionServiceAspect.java中加入返回通知的方法

public void doAfterRuturning(JoinPoint jp){
        System.out.println("返回通知");
    }

applicationContext.xml在AOP中配置返回通知

  <!-- AOP配置 -->
    <aop:config>
        <!-- 配置一个切面 -->
        <aop:aspect id="actionServiceAspect" ref="actionServiceAspect">
            <!-- 定义个切点: expression方法表达式-->
            <aop:pointcut expression="execution( * com.java.service.*.*(..))" id="pointCut"/>
             <!-- 返回通知 -->
            <aop:after-returning method="doAfterRuturning" pointcut-ref="pointCut"/>
        </aop:aspect>
    </aop:config>

执行结果:

执行参数:ActionParam===执行动作进行中......
返回通知

返回通知类似后置通知,觉得有点怪异。

4.异常通知

在操作类ActionServiceImpl中添加异常的方法:

    public void addAction(String name) {
        System.out.println("执行参数:"+name+"===执行动作进行中......");
        System.out.println((1/0));
    }

在ActionServiceAspect.java中加入异常通知的方法

    public void doAfterThrowing(JoinPoint pj,Throwable ta){
        System.out.println("异常通知");
        System.out.println("打印异常:"+ta.getMessage());
    }

applicationContext.xml在AOP中配置异常通知

    <!-- AOP配置 -->
    <aop:config>
        <!-- 配置一个切面 -->
        <aop:aspect id="actionServiceAspect" ref="actionServiceAspect">
            <!-- 定义个切点: expression方法表达式-->
            <aop:pointcut expression="execution( * com.java.service.*.*(..))" id="pointCut"/> 
            <!-- 异常通知 -->
            <aop:after-throwing method="doAfterThrowing" pointcut-ref="pointCut" throwing="ta"/>
        </aop:aspect>
    </aop:config>

执行结果:

执行参数:ActionParam===执行动作进行中......
异常通知
打印异常:/ by zero
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at com.java.service.impl.ActionServiceImpl.addAction(ActionServiceImpl.java:16)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

下面我们再试下这几种方式一起执行看看执行的顺序:
完整的applicationContext.xml:

<?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">

    <bean id="actionServiceAspect" class="com.java.advice.ActionServiceAspect"></bean>

    <bean id="actionService" class="com.java.service.impl.ActionServiceImpl"></bean>

    <!-- AOP配置 -->
    <aop:config>
        <!-- 配置一个切面 -->
        <aop:aspect id="actionServiceAspect" ref="actionServiceAspect">
            <!-- 定义个切点: expression方法表达式-->
            <aop:pointcut expression="execution( * com.java.service.*.*(..))" id="pointCut"/>
             <!-- 前置通知 -->
            <aop:before method="doBefore" pointcut-ref="pointCut"/>
            <!-- 后置通知 -->
            <aop:after method="doBeAfter" pointcut-ref="pointCut"/>
            <!-- 配置环绕通知 -->
            <aop:around method="doAround" pointcut-ref="pointCut"/>
            <!-- 返回通知 -->
            <aop:after-returning method="doAfterRuturning" pointcut-ref="pointCut"/>
            <!-- 异常通知 -->
            <aop:after-throwing method="doAfterThrowing" pointcut-ref="pointCut" throwing="ta"/>
        </aop:aspect>
    </aop:config>

</beans>

执行结果:

前置通知
操作的类名:com.java.service.impl.ActionServiceImpl
操作的方法名:addAction
执行方法参数:ActionParam
执行动作前(环绕通知)..........
执行参数:ActionParam===执行动作进行中......
打印异常(异常通知):/ by zero
执行动作完成(后置通知)
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at com.java.service.impl.ActionServiceImpl.addAction(ActionServiceImpl.java:16)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值