• Spring AOP快速入门----XML方式和注解方式


    一、AOP概念(面向切面编程)

    1. AOP优点是在不修改源码的情况下,对方法进行增强,使得代码易于维护,提高了开发效率。

    2. Spring的AOP底层原理的是动态代理方式(jdk和cglib两种常用动态代理方式),通过Spring的封装,只需要对Spring核心配置文件applicationContext.xml文件进行相应配置即可实现AOP。


    二、AOP相关术语

    • Target(目标对象):代理的目标对象;
    • Proxy(代理对象):目标对象被AOP织入增强后,产生的结果类;
    • JoinPoint(连接点):可以被AOP织入增强的点(方法);
    • Pointcut(切入点):从连接点中选取,进行AOP织入增强的点(方法);
    • Advice(通知/增强):对连接点(方法)进行的增强操作;
    • Aspect(切面):切点+通知;
    • Weaving(织入):对切入点进行增强,并创建代理对象的过程;

    三、AOP开发过程

    1. 编写核心业务代码:目标类的目标方法;
    2. 编写切面类,并在切面类中编写增强方法(通知);
    3. 在applicationContext.xml中配置织入关系:将增强方法对应到连接点;

    注1: 通过Spring框架监控切入点的方法的执行,使用代理机制,动态创建目标对象的代理对象,根据增强方法的类别(before,after,around…),在代理对象的对应位置,将增强方法织入。】
    注2: 在Spring中,框架会根据目标类是否有接口来决定采用哪种代理方式】

    四、基于XML的AOP开发

    1. 在pom.xml中导入需要的坐标;
    <?xml version="1.0" encoding="UTF-8"?>
    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>SpringAOP</groupId>
      <artifactId>SpringAOP</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>war</packaging>
    
      <dependencies>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>5.3.18</version>
        </dependency>
        <dependency>
          <groupId>org.aspectj</groupId>
          <artifactId>aspectjweaver</artifactId>
          <version>1.8.4</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-test</artifactId>
          <version>5.2.5.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.10</version>
        </dependency>
    
      </dependencies>
    
    </project>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    2.创建目标接口,目标类,目标方法;
    package com.aop;
    
    public interface TargetInterface {
        void save();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    package com.aop;
    
    public class Target implements TargetInterface {
        public void save() {
            System.out.println("<<目标方法执行...>>");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    3. 创建切面类和增强方法;
    package com.aop;
    
    public class Aspect {
        public void beforeMethod(){
            System.out.println("<<前置增强方法...>>");
        }
    
        public void afterReturningMethod(){
            System.out.println("<<后置增强方法...>>");
        }
        
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    4. 配置织入关系;
    <?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="target" class="com.aop.Target"></bean>
    
        <!--切面对象-->
        <bean id="aspect" class="com.aop.Aspect"></bean>
    
        <!--配置织入-告诉spring框架,哪些方法(切点)需要进行哪些增强-->
        <aop:config>
            <!--声明切面-->
            <aop:aspect ref="aspect">
            <!--抽取切点表达式-->
                <!--<aop:pointcut id="pointCut" expression="execution(public void com.aop.Target.save())"></aop:pointcut>-->          
                <aop:before method="beforeMethod" pointcut="execution(public void com.aop.Target.save())"></aop:before>
                <aop:after method="afterReturningMethod" pointcut="execution(public void com.aop.Target.save())"></aop:after>
            </aop:aspect>
        </aop:config>
    
    </beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    • 切点表达式语法:execution(修饰符 返回值类型 包名.类名.方法名(参数))

      • 访问修饰符可以省略;
      • 返回值类型,包名,类名,方法名可以使用 * 替代,代表 :任意;
      • 包名和类名之间一个 . 代表当前包下的类,两个 . 代表当前包及其子包下的类;
      • 参数列表使用两个 . 表示任意类型的参数列表;
      • execution(public void com.aop.Target.save());
      • execution(* com . aop . *. * ( . . ));
      • execution(* com . aop . . * . * (. .));

    • 增强(通知)类型:pointcut=“切点表达式”>

    名称标签说明
    前置通知< aop:before />指定增强方法在切入点之前执行
    后置通知< aop:after-returning />指定增强方法在切入点之后执行
    环绕通知< aop:around />指定增强方法在切入点之前和之后都执行
    异常抛出通知< aop:throwing />指定增强方法在目标方法出现异常时执行
    最终通知< aop:after />无论目标方法是否出现异常,都执行
    • 切点表达式抽取:不同的通知类型对应同一切点表达式时,可对表达式进行抽取;
     <aop:pointcut id="pointCut" expression="execution(public void com.aop.Target.save())"></aop:pointcut>-->
    
    • 1
    5. 测试与结果
    package test;
    import com.aop.TargetInterface;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class AopTest {
        @Test
        public void test1(){
            ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
            //使用TargetInterface 说明被增强后的对象即(proxy对象)和原来的target对象是兄弟关系,所以用父类接口实现
            TargetInterface target = (TargetInterface) app.getBean("target");
            target.save();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

    四、基于注解的AOP开发

    1. 创建目标接口,目标类,目标方法(上同);
    2. 创建切面类和增强方法(上同);
    3. 将目标类和切面类的对象创建权交给spring;
    package com.aop;
    
    import org.springframework.stereotype.Component;
    
    @Component("target") //由spring产生bean对象
    public class Target implements TargetInterface {
        public void save() {
            System.out.println("<<目标方法执行...>>");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    4. 在切面类中使用注解配置织入关系;
    package com.aop;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.stereotype.Component;
    
    @Component("aspect")
    @org.aspectj.lang.annotation.Aspect //标注当前类是切面类
    public class Aspect {
    
        // 配置前置通知
        @Before(value = "execution(void com.aop.Target.save())")
        public void beforeMethod(){
            System.out.println("<<前置增强方法...>>");
        }
    
        // 配置后置通知
        @AfterReturning(value = "pointcut()")
        public void afterReturningMethod(){
            System.out.println("<<后置增强方法...>>");
        }
        
        // 定义切点表达式方法,用于抽取
        @Pointcut("execution(void com.aop.Target.save())")
        public void pointcut(){
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 增强(通知)类型:@通知类型(value = “切点表达式”)
    名称标签说明
    前置通知@Befoe指定增强方法在切入点之前执行
    后置通知@AfterReturning指定增强方法在切入点之后执行
    环绕通知@Around指定增强方法在切入点之前和之后都执行
    异常抛出通知@AfterThrowing指定增强方法在目标方法出现异常时执行
    最终通知@After无论目标方法是否出现异常,都执行
    5. 在配置文件中开启组件扫描和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:context="http://www.springframework.org/schema/context"
           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
                               http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd
                                   ">
        <!--组件扫描-->
        <context:component-scan base-package="com.aop"></context:component-scan>
    
        <!--AOP自动代理-->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    </beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    6. 测试与结果;
    package test;
    import com.aop.TargetInterface;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class AopTest {
        @Test
        public void test1(){
            ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
            //使用TargetInterface 说明被增强后的对象即(proxy对象)和原来的target对象是兄弟关系,所以用父类接口实现
            TargetInterface target = (TargetInterface) app.getBean("target");
            target.save();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

  • 相关阅读:
    05-内存分配与回收策略
    【Shell】Shell脚本入门
    GO微服务实战第五节 为什么说 Service Meh 是下一代微服务架构?
    安装插件失败,getaddrinfo ENOENT raw.githubusercontent.com 报错
    Go基础语法:变量和常量
    年度新旗舰南卡Runner Pro4骨传导耳机评测,解放双耳,运动不设限
    css 灰质彩色的边框
    C++——异常
    【电商API详解】阿里巴巴中国站获得1688商品详情 API 返回值说明
    1.74HC138控制LED发光
  • 原文地址:https://blog.csdn.net/weixin_43563049/article/details/126634527