zoukankan      html  css  js  c++  java
  • 18-spring学习-AOP深入操作

    范例:定义一个参数拦截

    package com.Spring.aop;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class ServiceAspect {
        
        public void serviceBefore()
        {
            System.out.println("AOP切面执行日志记录操作");
        }
        
        public void serviceBefore2(Object arg)
        {
            System.out.println("AOP切面执行增加前操作,参数="+arg);
        }
        public void serviceAfter()
        {
            System.out.println("AOP切面执行事务处理操作");
        }
    }

    配置也修改:

    <aop:config>
        <!-- 定义程序的切入点 -->
            <aop:pointcut expression="execution(* com.Spring..*.*(..)))" id="pointcut"/>
            <!-- 这里ref的对象是通过annotation配置@Component出来的, -->
            <!-- 定义面向方面的处理类 -->
            <aop:aspect ref="serviceAspect">
                <aop:before method="serviceBefore2" pointcut-ref="pointcut"/>
                <aop:after method="serviceAfter"  pointcut-ref="pointcut"/>
            </aop:aspect>
        </aop:config>
        <aop:aspectj-autoproxy  proxy-target-class="true"/>

    此时运行报错。

    此时serviceBefore2方法有参数了,就需要修改了。

    范例:定义切入点表达式

    这里通过 and args()  和arg-names来指定要传入操作前方法的参数。 

        <aop:config>
        <!-- 定义程序的切入点 -->
            <aop:pointcut expression="execution(* com.Spring..*.*(..)) and args(vo))" id="pointcut"/>
            <!-- 这里ref的对象是通过annotation配置@Component出来的, -->
            <!-- 定义面向方面的处理类 -->
            <aop:aspect ref="serviceAspect">
                <aop:before method="serviceBefore2" pointcut-ref="pointcut" arg-names="vo"/>
                <aop:after method="serviceAfter"  pointcut="execution(* com.Spring..*.*(..)))"/>
            </aop:aspect>
        </aop:config>
        <aop:aspectj-autoproxy  proxy-target-class="true"/>

    运行结果:

    因为after方法没有参数,不能直接使用第一个定义的切入点,所以这里after方法重新指定一个切入点,

    而before是有参数的,直接使用第一个定义的切入点就行了。

    除了操作之前拦截,也可以针对返回的结果进行拦截。

    范例:针对返回结果拦截

    package com.Spring.aop;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class ServiceAspect {
        
        public void serviceBefore()
        {
            System.out.println("AOP切面执行日志记录操作");
        }
        
        public void serviceBefore2(Object arg)
        {
            System.out.println("AOP切面执行增加前操作,参数=" +arg);
        }
        public void serviceAfter()
        {
            System.out.println("AOP切面执行事务处理操作");
        }
        public void serviceAfterReturn(Object val)    //表示操作结果
        {
            System.out.println("AOP切面操作完成,返回结果:"+val);
        }
    }

    配置里面修改:

        <aop:config>
        <!-- 定义程序的切入点 -->
            <aop:pointcut expression="execution(* com.Spring..*.*(..)) and args(vo))" id="pointcut"/>
            <!-- 这里ref的对象是通过annotation配置@Component出来的, -->
            <!-- 定义面向方面的处理类 -->
            <aop:aspect ref="serviceAspect">
                <aop:before method="serviceBefore2" pointcut-ref="pointcut" arg-names="vo"/>
                <aop:after method="serviceAfter"  pointcut="execution(* com.Spring..*.*(..)))"/>
                <aop:after-returning method="serviceAfterReturn" pointcut="execution(* com.Spring..*.*(..)))"  returning="haha" arg-names="haha"/>
            </aop:aspect>
        </aop:config>

    这里通过returning和arg-names来传递返回结果给操作完成后返回方法:serviceAfterReturn,做完这个方法的参数。

     执行结果:

    除了返回结果的拦截之外,还能进行异常处理的拦截操作。

    范例:修改MemberServiceImpl

    package com.Spring.Test;
    
    import org.apache.commons.lang.NullArgumentException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import com.Spring.Service.IMemberService;
    import com.Spring.Service.Impl.MemberServiceImpl;
    import com.Spring.Vo.Member;
    
    public class TestMemberService {
        
        public static void main(String args[])
        {
            throw new NullArgumentException("我来抛出一个异常");
            /*
            ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
            IMemberService ser=ctx.getBean("memberServiceImpl",MemberServiceImpl.class);
            Member vo=new Member();
            vo.setMid("hello");
            vo.setName("你好");
            System.out.println(ser.insert(vo));
            */
        }
    }

    增加拦截处理操作

    package com.Spring.aop;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class ServiceAspect {
        
        public void serviceBefore()
        {
            System.out.println("AOP切面执行日志记录操作");
        }
        
        public void serviceBefore2(Object arg)
        {
            System.out.println("AOP切面执行增加前操作,参数=" +arg);
        }
        public void serviceAfter()
        {
            System.out.println("AOP切面执行事务处理操作");
        }
        public void serviceAfterReturn(Object val)    //表示操作结果
        {
            System.out.println("AOP切面操作完成,返回结果:"+val);
        }
        
        public void serviceAfterThrow(Exception e)    //表示操作结果
        {
            System.out.println("AOP切面操作出现异常:"+e);
        }
    }

    配置:

        <aop:config>
        <!-- 定义程序的切入点 -->
            <aop:pointcut expression="execution(* com.Spring..*.*(..)) and args(vo))" id="pointcut"/>
            <!-- 这里ref的对象是通过annotation配置@Component出来的, -->
            <!-- 定义面向方面的处理类 -->
            <aop:aspect ref="serviceAspect">
                <aop:before method="serviceBefore2" pointcut-ref="pointcut" arg-names="vo"/>
                <aop:after method="serviceAfter"  pointcut="execution(* com.Spring..*.*(..)))"/>
                <aop:after-returning method="serviceAfterReturn" pointcut="execution(* com.Spring..*.*(..)))"  returning="haha" arg-names="haha"/>
                <aop:after-throwing method="serviceAfterThrow" pointcut="execution(* com.Spring..*.*(..)))" arg-names="e" throwing="abc"/>
            </aop:aspect>
        </aop:config>
        <aop:aspectj-autoproxy  proxy-target-class="true"/>

    这里因为需要传递异常参数,所以需要arg-names和throwing,但是这两个的值随便写就像了,不用想对应起来。

    运行结果:

    以上几个拦截器已经可以处理AOP可以处理的范畴。但是为了简化,整个AOP还提供环绕通知,

    即一个方法可以处理所有的aop操作,这种操作更像代理结构:

    范例:增加环绕处理

    但是必须考虑接收参数的情况,而接收的参数类型只能是一种类型:ProceedingJoinPoint,通过此类型可以取得全部的提交参数信息。

        public Object serviceAround(ProceedingJoinPoint point) throws Throwable
        {
            System.out.println("AOP切面数据层方法调用之前,参数:"+Arrays.toString(point.getArgs()));
            Member vo=new Member();
            vo.setMid("TestAOP");
            vo.setName("测试AOP");
            Object retVal=point.proceed(new Object[]{ vo });  //retVal接收方法数据层调用之后的结果
            System.out.println("AOP切面数据层方法调用之后,返回值:"+retVal);
            return true;
        }

    在整个环绕拦截之中,用户可以任意修改传递的参数数据,也可以修改返回的结果。

    配置环绕拦截:

    <aop:around method="serviceAround" pointcut="execution(* com.Spring..*.*(..)))" />

    执行结果:

    所以,在所有AOP操作中,环绕的功能是最强大的。其他拦截只能做一些信息记录,而环绕可以对传入的参数和返回结果进行控制。

  • 相关阅读:
    ES6核心内容精讲--快速实践ES6(三)
    ES6核心内容精讲--快速实践ES6(二)
    ES6核心内容精讲--快速实践ES6(一)
    webpack入门
    centos 7 nodejs 安装
    android结合Jenkins使用V2签名
    dockerfile 创建Jenkins镜像
    ubuntu docker 安装
    shell sed语法详解
    mac关于stf开源工具安装
  • 原文地址:https://www.cnblogs.com/alsf/p/8207380.html
Copyright © 2011-2022 走看看