zoukankan      html  css  js  c++  java
  • spring学习(十八)--AOP切面编程

      不同于OOP--面向对象编程,提供一系列继承、重写、封装技术,纵向的丰富编程功能。spring AOP为面向横向的切面编程,当工程中很多类都有共同的需求时,可以针对这些类,将共用的方法抽离出来,形成一个切面方法,将他织入到这些类中。每当执行这些类的时候,自动触发织入的切面方法,这样就不用在这些类中写重复的代码。

    一 AOP的基本概念

    (1)Aspect(切面):通常是一个类,里面可以定义切入点和通知

    (2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用

    (3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around

    (4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式

    (5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类

    二 Spring AOP

    Spring中的AOP代理还是离不开Spring的IOC容器,代理的生成,管理及其依赖关系都是由IOC容器负责,Spring默认使用JDK动态代理,在需要代理类而不是代理接口的时候,Spring会自动切换为使用CGLIB代理,不过现在的项目都是面向接口编程,所以JDK动态代理相对来说用的还是多一些。

    AOP有两种实现方式,一种基于XML配置,一种基于注解,本篇先写一个基于XML配置的例子,下篇中讲解基于注解的AOP编程。

     1、在spring中使用AOP变成,不止要导入spring-aop.jar,还需要导入spring-aspects.jar、aspectjweaver.jar和aopalliance.jar,但是aspectjweaver.jar被spring-aspects.jar依赖,aopalliance.jar被spring-aop.jar依赖,spring-aop.jar又被spring-mvc.jar依赖,所以只要导入spring-mvc.jar和spring-aspects.jar就行了。

    pom.xml文件:

      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.version>4.0.5.RELEASE</spring.version>
      </properties>
    
      <dependencies>
      
      <!-- springMvc框架,它依赖于spring的其他jar包,会自动导入spring的core、beans、web等jar包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>

    2、编写被增强的类,即被织入切面的类LittleBallImpl.java:

    package springAop;
    
    public class LittleBallImpl {
        
        /* 
         * 需要aop代理的方法
         * getLittleBallName()
         */
        public void getLittleBallName(String name){
            
            System.out.println("hello, I am little ball!");
        }
    }

    3、编写方法执行前、执行后、执行前后的增强类PrintDate.java、PrintWeather.java、AroundPoint.java,其中PrintDate通过在切入方法入参中添加JointPoint来获取被切方法的入参:

    package springAop;
    
    import java.util.Date;
    import org.aspectj.lang.JoinPoint;
    
    /**
     * 切面类
     * @author qiaozhong
     */
    public class PrintDate {
    
        /**
         * 织入的具体业务方法,实现业务逻辑
         * JointPoint可获得被切的方法的入参
         */
        public void printDate(JoinPoint joinPoint){
            //获取被切的方法的入参
            Object[] o=joinPoint.getArgs();
            
            System.out.println(String.valueOf(o[0]) + new Date());
        }
    }
    package springAop;
    
    
    public class PrintWeather {
    
        /**
         * 织入的具体业务方法,实现业务逻辑
         */
        public void printWeather(){
            System.out.println("Today is sunny");
        }
    }
    package springAop;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    
    public class AroundPoint {
        /*
         * 环绕通知
         * */
        public void aroundPrint(ProceedingJoinPoint point) throws Throwable {
            System.out.println("环绕通知前。。。。。");
            point.proceed();
            System.out.println("环绕通知后。。。。。。");
        }
    }

    4、配置切面的配置文件spring-aop.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"
        xmlns:context="http://www.springframework.org/schema/context"
        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-4.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
        <!-- 配置bean -->
        <bean id="littleBall" class="springAop.LittleBallImpl"></bean>
        <!-- 配置切面的bean -->
        <bean id="printDate" class="springAop.PrintDate"></bean>    
        <bean id="printWeather" class="springAop.PrintWeather"></bean>
        <bean id="aroundPoint" class="springAop.AroundPoint"></bean>
    
        <!-- 配置AOP -->
        <aop:config>
            <!-- 配置切面和通知  order:优先级,越小优先级越高-->
            <aop:aspect id="date" ref="printDate" order="1">
            <!-- 配置切面表达式 -->
            <aop:pointcut id="addDate" expression="execution(* springAop.LittleBallImpl.get*(..))" />
                <!-- 配置切面方法 -->
                <aop:before method="printDate" pointcut-ref="addDate"/>
                <aop:after method="printDate" pointcut-ref="addDate"/>
            </aop:aspect>
            
            <!-- 配置切面和通知  order:优先级,越小优先级越高-->
            <aop:aspect id="weather" ref="printWeather" order="2">
            <!-- 配置切面表达式 -->
            <aop:pointcut id="addWeather" expression="execution(* springAop.LittleBallImpl.get*(..))" />
                <!-- 配置切面方法 -->
                <aop:before method="printWeather" pointcut-ref="addWeather"/>
                <aop:after method="printWeather" pointcut-ref="addWeather"/>
            </aop:aspect>
            
            <!-- 配置切面和通知  order:优先级,越小优先级越高-->
            <aop:aspect id="aroundP" ref="aroundPoint" order="3">
            <!-- 配置切面表达式 -->
            <aop:pointcut id="aPoint" expression="execution(* springAop.LittleBallImpl.get*(..))" />
                <!-- 配置切面方法 -->
                <aop:around method="aroundPrint" pointcut-ref="aPoint"/>
            </aop:aspect>
        </aop:config>
    </beans>

    5、编写测试类TestAop.java:

    package springAop;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestAop {
    
        public static void main(String[] args) {
            ApplicationContext ac = new ClassPathXmlApplicationContext("springConfig/spring-aop.xml");
            LittleBallImpl littleBallImpl = (LittleBallImpl)ac.getBean(LittleBallImpl.class);
            littleBallImpl.getLittleBallName("hello ,I am little ball! Today is ");
        }
    }

    测试结果:

    hello ,I am little ball! Today is Thu Oct 31 14:35:43 CST 2019
    Today is sunny
    环绕通知前。。。。。
    hello, I am little ball!
    环绕通知后。。。。。。
    Today is sunny
    hello ,I am little ball! Today is Thu Oct 31 14:35:43 CST 2019

    结果分析:

    1、先执行了addDate切面方法,通过JointPoint获取了被切方法的入参“hello ,I am little ball! Today is”

    2、执行了addWeather切面方法

    3、执行AroundPoint切面前置方法

    4、执行业务类LittleBallImpl

    5、执行AroundPoint切面后置方法

    6、执行了addWeather切面方法

    7、执行了addDate切面方法,通过JointPoint获取了被切方法的入参“hello ,I am little ball! Today is”

    个人理解,如有错误,欢迎指正!
  • 相关阅读:
    python运算学习之Numpy ------ 算术运算
    一招教你如何在简历上突出工作经验!
    【软件测试工程师】跳槽到大厂需要具备什么资历和技能?
    LoadRunner性能测试系统学习教程:脚本编写之参数化技术(4)
    Python+Selenium自动化测试教程连载(3)
    测试人员在职场中如何提升自己的沟通能力?
    LoadRunner性能测试系统学习教程:脚本编写之Block(块)技术与参数化(3)
    转行月入10K+的人,背后是付出怎么样的努力呢?
    LoadRunner性能测试系统学习教程:脚本编写之检查点函数(2)
    Python+Selenium自动化测试教程连载(2)
  • 原文地址:https://www.cnblogs.com/gllegolas/p/11771506.html
Copyright © 2011-2022 走看看