zoukankan      html  css  js  c++  java
  • 【Spring入门系列】篇6:再探SpringAOP(SpringAOP的使用)

    前言

    前面一篇文章中我们简单介绍了SpringAOP的作用以及原理,接下来我们来讲讲SpringAOP怎么配置使用。

    一、SpringAOP的基本使用

    还是使用上篇中的例子,假设我们需要给GoodsDao类进行增强:

    public class GoodsDao {
        public void save() {
            System.out.println("goodsDao-----save");
        }
    }
    

    1.编写切面类

    切面类中主要包含了多个通知(增强功能所封装成的方法)

    public class MyAspectXML {
        public void check() {
            System.out.println("增加权限校验");
        }
    }
    

    2.配置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="goodsDao" class="demo1.GoodsDao"></bean>
        <bean id="myAspect" class="demo2.MyAspectXML"></bean>
    
        <!--配置Aop-->
        <aop:config>
            <!--配置切点:需要增强的方法-->
            <aop:pointcut id="savePoint" expression="execution(* demo1.GoodsDao.save(..))"/>
            <!--配置切面:如何增强、增强的功能-->
            <aop:aspect ref="myAspect">
                <aop:before method="check" pointcut-ref="savePoint"/>
            </aop:aspect>
    
        </aop:config>
    
    </beans>
    

    第一步:配置applicationContext肯定是将需要增强的类、切面类交由Spring管理

        <bean id="goodsDao" class="demo1.GoodsDao"></bean>
        <bean id="myAspect" class="demo2.MyAspectXML"></bean>
    

    第二步:在aop配置配置切点,我们当然要指定需要被增强的方法(切点)。expression表达式指定需要配置的方法,*表示任意返回值..表示任意参数。

    <!--配置切点:需要增强的方法-->
    <aop:pointcut id="savePoint" expression="execution(* demo1.GoodsDao.save(..))"/>
    

    第三步:配置切面,配置完切点我们还需要配置切面来通知Spring需要增强的内容是什么,以及如何进行增强

    <!--配置切面:如何增强、增强的功能-->
    <aop:aspect ref="myAspect">
    <aop:before method="check" pointcut-ref="savePoint"/>
    </aop:aspect>
    

    3.测试

    import demo1.GoodsDao;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import javax.annotation.Resource;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext.xml")
    public class AspectTest {
    
        @Resource(name = "goodsDao")
        GoodsDao goodsDao;
    
        @Test
        public void test() {
            goodsDao.save();
        }
    }
    

    运行结果:

    增加权限校验
    goodsDao-----save
    

    二、SpringAOP通知类型

    在动态代理中我们提到过我们可以在方法前面进行增强,也可以在方法后进行增强,springAOP也是如此,给我们提供了下面几种方式:

    • 前置通知(before):在方法执行前通知
    • 后置通知(after-returning):在方法执行后通知
    • 环绕通知(around):在方法执行前后通知
    • 异常抛出通知(after-throwing):在方法发生异常时通知
    • 最终通知(after):无论是否发生异常都通知

    我们先将GoodsDao修改一下:

    public class GoodsDao {
        public void save() {
            System.out.println("goodsDao-----save");
        }
    
        public String delete() {
            System.out.println("delete");
            return "delete---return";
        }
    
        public void update() {
            System.out.println("update");
        }
    
        public void find() {
            System.out.println("find");
            int a = 1/0;
        }
    
    }
    

    接着修改一下切面类:

    import org.aspectj.lang.ProceedingJoinPoint;
    
    public class MyAspectXML {
        public void check() {
            System.out.println("增加权限校验");
        }
    
        public void writeLog(Object res) {
            System.out.println(res);
            System.out.println("记入日志");
        }
    
        public void around(ProceedingJoinPoint joinPoint) throws Throwable {
            System.out.println("around------前置通知");
            joinPoint.proceed();
            System.out.println("around------后置通知");
        }
    
        public void exceptionNotice(Throwable e) {
            System.out.println("发生了异常:"+ e.getMessage());
        }
    
        public void finalNotice() {
            System.out.println("final--------------");
        }
    
    }
    

    配置applicationContex.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="goodsDao" class="demo1.GoodsDao"></bean>
        <bean id="myAspect" class="demo2.MyAspectXML"></bean>
    
        <!--配置Aop-->
        <aop:config>
            <!--配置切点:需要增强的方法-->
            <aop:pointcut id="savePoint" expression="execution(* demo1.GoodsDao.save(..))"/>
            <aop:pointcut id="deletePoint" expression="execution(* demo1.GoodsDao.delete(..))"/>
            <aop:pointcut id="updatePoint" expression="execution(* demo1.GoodsDao.update(..))"/>
            <aop:pointcut id="findPoint" expression="execution(* demo1.GoodsDao.find(..))"/>
            <!--配置切面:如何增强、增强的功能-->
            <aop:aspect ref="myAspect">
                <!--前置通知-->
                <aop:before method="check" pointcut-ref="savePoint"/>
                <!--后置通知-->
                <aop:after-returning method="writeLog" returning="res" pointcut-ref="deletePoint"/>
                <!--环绕通知-->
                <aop:around method="around" pointcut-ref="updatePoint"/>
                <!--异常抛出通知-->
                <aop:after-throwing method="exceptionNotice" throwing="e" pointcut-ref="findPoint"/>
                <!--最终通知-->
                <aop:after method="finalNotice" pointcut-ref="findPoint"/>
    
            </aop:aspect>
    
        </aop:config>
    
    </beans>
    

    测试类:

    import demo1.GoodsDao;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import javax.annotation.Resource;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext.xml")
    public class AspectTest {
    
        @Resource(name = "goodsDao")
        GoodsDao goodsDao;
    
        @Test
        public void test() {
            goodsDao.save();
            System.out.println("--------------------------------------------");
            goodsDao.delete();
            System.out.println("--------------------------------------------");
            goodsDao.update();
            System.out.println("--------------------------------------------");
            goodsDao.find();
        }
    }
    

    运行结果:

    增加权限校验
    goodsDao-----save
    --------------------------------------------
    delete
    delete---return
    记入日志
    --------------------------------------------
    around------前置通知
    update
    around------后置通知
    --------------------------------------------
    find
    final--------------
    发生了异常:/ by zero
    

    三、SpringAOP注解编程

    我们可以将上面的程序改为注解的形式:

    修改applicationContex.xml,需要在配置中开启aop注解:

    <?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="goodsDao" class="demo1.GoodsDao"></bean>
        <bean id="myAspect" class="demo2.MyAspectXML"></bean>
    
        <!--AOP开启注解-->
        <aop:aspectj-autoproxy/>
    </beans>
    

    修改切面类,用法与配置文件形式基本相同:

    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    
    @Aspect
    public class MyAspectXML {
    
        @Before(value = "execution(* demo1.GoodsDao.save(..))")
        public void check() {
            System.out.println("增加权限校验");
        }
    
        @AfterReturning(value = "execution(* demo1.GoodsDao.delete(..))" , returning = "res")
        public void writeLog(Object res) {
            System.out.println(res);
            System.out.println("记入日志");
        }
    
        @Around(value = "execution(* demo1.GoodsDao.update(..))")
        public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
            System.out.println("around------前置通知");
            Object proceed = joinPoint.proceed();
            System.out.println("around------后置通知");
            return proceed;
        }
    
        @AfterThrowing(value = "execution(* demo1.GoodsDao.find(..))" , throwing = "e")
        public void exceptionNotice(Throwable e) {
            System.out.println("发生了异常:"+ e.getMessage());
        }
    
        @After(value = "execution(* demo1.GoodsDao.find(..))")
        public void finalNotice() {
            System.out.println("final--------------");
        }
    
    }
    
    注解切入点的配置

    有时候我们想在一个切点中即添加前置通知,又添加异常通知和最终通知该如何操作呢?

    我们可以在切面当中定义好切入点:

    import org.aspectj.lang.annotation.*;
    
    @Aspect
    public class MyAspectXML2 {
        @Before(value = "MyAspectXML2.pointcut1()")
        public void check() {
            System.out.println("增加权限校验");
        }
    
        @AfterThrowing(value = "MyAspectXML2.pointcut1()" , throwing = "e")
        public void exceptionNotice(Throwable e) {
            System.out.println("发生了异常:"+ e.getMessage());
        }
    
        @After(value = "MyAspectXML2.pointcut1()")
        public void finalNotice() {
            System.out.println("final--------------");
        }
    
        @Pointcut(value = "execution(* demo1.GoodsDao.save(..))")
        public void pointcut1(){}//定义好切点
    }
    
  • 相关阅读:
    JavaScript 原型和原型链 prototype
    javascript dom 表单元素之 radio
    JavaScript Dom 表单元素之 checkbox
    JavaScript DOM 表单元素之 select
    JavaScript-ECMAScript 之模块
    Javascript--ECMAScript 之 this
    Javascript-ECMAscript--Array.prototype.slice() 方法
    JavaScript -ECMAScriopt: Array.prototype.slice.call()详解及转换数组的方法
    JavaScript-ECMASCript apply call bind
    requests的深入刨析及封装调用
  • 原文地址:https://www.cnblogs.com/ThinMoon/p/13219644.html
Copyright © 2011-2022 走看看