欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

【Spring】AOP详解

程序员文章站 2022-05-18 18:17:52
本文目录AOP概述Spring基于代理类AOP实现前置通知返回后通知环绕通知异常通知AOP概述AOP(Aspect-Oriented Programming)面向切面编程,是Spring框架体系结构中重要的功能模块,在代码执行过程中,动态嵌入其他代码,通常使用在如日志、事务处理、异常处理等场景。AOP 术语术语描述切面切面泛指交叉业务逻辑。比如事务处理、日志处理就可以理解为切面。常用的切面有通知与顾问。实际就是对主业务逻辑的一种增强织入织入是指将切面代码插入到目标对象的...

AOP概述

AOP(Aspect-Oriented Programming)面向切面编程,是Spring框架体系结构中重要的功能模块,在代码执行过程中,动态嵌入其他代码,通常使用在如日志、事务处理、异常处理等场景。
AOP 术语

术语 描述
切面 切面泛指交叉业务逻辑。比如事务处理、日志处理就可以理解为切面。常用的切面有通知与顾问。实际就是对主业务逻辑的一种增强
织入 织入是指将切面代码插入到目标对象的过程。
连接点 连接点指切面可以织入的位置。
切入点 切入点指切面具体织入的位置。
通知(Advice) 通知是切面的一种实现,可以完成简单织入功能(织入功能就是在这里完成的)。通知定义了增强代码切入到目标代码的时间点,是目标方法执行之前执行,还是之后执行等。通知类型不同,切入时间不同。
目标对象 被一个或者多个方面所通知的对象,这个对象永远是一个被代理对象。也称为被通知对象。
织入 织入把方面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时,类加载时和运行时完成。

通知的类型

通知 描述
前置通知 在一个方法执行之前,执行通知。
后置通知 在一个方法执行之后,不考虑其结果,执行通知。
返回后通知 在一个方法执行之后,只有在方法成功完成时,才能执行通知
抛出异常后通知 在一个方法执行之后,只有在方法退出抛出异常时,才能执行通知。
环绕通知 在建议方法调用之前和之后,执行通知。

Spring基于代理类AOP实现

前面介绍了Java中代理模式和JDK提供的动态代理:Java代理模式之-静态代理和动态代理原理解析
Spring 默认使用JDK动态代理实现的AOP编程

首先创建Spring工程:【Spring】Spring入门案例

pom.xml中加入Spring aop相关的包

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>5.2.7.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>aopalliance</groupId>
      <artifactId>aopalliance</artifactId>
      <version>1.0</version>
    </dependency>

前置通知

代码结构如下:
【Spring】AOP详解

创建目标接口和实现类

public interface UserService {
    public void selectUser();
}
public class UserServiceImpl implements UserService{
    @Override
    public void selectUser() {
        System.out.println("UserServiceImpl -> selectUser");
    }
}

创建切面类

public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
    /**
     * method 目标方法
     * args 目标方法参数列表
     * target 目标对象
     */
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("MyMethodBeforeAdvice -> 前置通知的before方法执行...");
    }
}

添加配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 注册目标类 -->
    <bean id="userService" class="com.lucas.UserServiceImpl" ></bean>
    <!-- 注册前置通知 -->
    <bean id="myMethodBeforeAdvice" class="com.lucas.MyMethodBeforeAdvice" ></bean>

    <!-- 注册代理类 -->
    <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!-- 指定目标对象 -->
        <property name="target" ref="userService"/>
        <!-- 指定目标类实现的所有接口 -->
        <property name="interfaces" value="com.lucas.UserService"/>
        <!-- 指定切面 -->
        <property name="interceptorNames" >
            <list>
                <value>myMethodBeforeAdvice</value>
            </list>
        </property>
    </bean>
</beans>

添加测试代码

public class App {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new
                ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) applicationContext.getBean("proxyFactoryBean");
        userService.selectUser();
    }
}

运行如下:
【Spring】AOP详解

返回后通知

添加返回后通知切面类


import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class MyAfterRunningAdvice implements AfterReturningAdvice {
    /**
     * method 目标方法
     * args 目标方法参数列表
     * target 目标对象
     */
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("MyAfterRunningAdvice -> 后置方法执行了...");
    }
}

修改配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 注册目标类 -->
    <bean id="userService" class="com.lucas.UserServiceImpl" ></bean>
    <!-- 注册前置通知 -->
    <bean id="myMethodBeforeAdvice" class="com.lucas.MyMethodBeforeAdvice" ></bean>
    <!-- 注册返回后通知 -->
    <bean id="myMethodAfterAdvice" class="com.lucas.MyAfterRunningAdvice" ></bean>
    <!-- 注册代理类 -->
    <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!-- 指定目标对象 -->
        <property name="target" ref="userService"/>
        <!-- 指定目标类实现的所有接口 -->
        <property name="interfaces" value="com.lucas.UserService"/>
        <!-- 指定切面 -->
        <property name="interceptorNames" >
            <list>
                <value>myMethodBeforeAdvice</value>
                <value>myMethodAfterAdvice</value>
            </list>
        </property>
    </bean>
</beans>

运行结果如下:
【Spring】AOP详解

环绕通知

创建环绕通知切面类

package com.lucas;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("MyMethodInterceptor -> 环绕通知 --- before");
        Object res = invocation.proceed();
        if(res !=null){
            // 增强返回结果
            res = ((String)res).toUpperCase();
        }
        System.out.println("MyMethodInterceptor 环绕通知---after");
        return res;
    }
}

修改配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 注册目标类 -->
    <bean id="userService" class="com.lucas.UserServiceImpl" ></bean>
    <!-- 注册前置通知 -->
    <bean id="myMethodBeforeAdvice" class="com.lucas.MyMethodBeforeAdvice" ></bean>
    <!-- 注册返回后通知 -->
    <bean id="myMethodAfterAdvice" class="com.lucas.MyAfterRunningAdvice" ></bean>
    <!-- 注册环绕通知 -->
    <bean id="myMethodInterceptor" class="com.lucas.MyMethodInterceptor" ></bean>
    <!-- 注册代理类 -->
    <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!-- 指定目标对象 -->
        <property name="target" ref="userService"/>
        <!-- 指定目标类实现的所有接口 -->
        <property name="interfaces" value="com.lucas.UserService"/>
        <!-- 指定切面 -->
        <property name="interceptorNames" >
            <list>
                <value>myMethodBeforeAdvice</value>
                <value>myMethodAfterAdvice</value>
                <value>myMethodInterceptor</value>
            </list>
        </property>
    </bean>
</beans>

运行结果
【Spring】AOP详解

异常通知

创建异常通知切面类

import org.springframework.aop.ThrowsAdvice;

public class MyThrowsAdvice implements ThrowsAdvice {

    public void afterThrowing(Exception ex){
        System.out.println("MyThrowsAdvice -> afterThrowing 异常通知");
    }
}

UserServiceImpl中制造异常

public class UserServiceImpl implements UserService {
    @Override
    public void selectUser() {
        System.out.println("UserServiceImpl -> selectUser");
        throw new NullPointerException();
    }
}

添加配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 注册目标类 -->
    <bean id="userService" class="com.lucas.UserServiceImpl" ></bean>
    <!-- 注册前置通知 -->
    <bean id="myMethodBeforeAdvice" class="com.lucas.MyMethodBeforeAdvice" ></bean>
    <!-- 注册返回后通知 -->
    <bean id="myMethodAfterAdvice" class="com.lucas.MyAfterRunningAdvice" ></bean>
    <!-- 注册环绕通知 -->
    <bean id="myMethodInterceptor" class="com.lucas.MyMethodInterceptor" ></bean>
    <!-- 异常通知 -->
    <bean id="myThrowsAdvice" class="com.lucas.MyThrowsAdvice" ></bean>
    <!-- 注册代理类 -->
    <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!-- 指定目标对象 -->
        <property name="target" ref="userService"/>
        <!-- 指定目标类实现的所有接口 -->
        <property name="interfaces" value="com.lucas.UserService"/>
        <!-- 指定切面 -->
        <property name="interceptorNames" >
            <list>
                <value>myMethodBeforeAdvice</value>
                <value>myMethodAfterAdvice</value>
                <value>myMethodInterceptor</value>
                <value>myThrowsAdvice</value>
            </list>
        </property>
    </bean>
</beans>

运行结果:

【Spring】AOP详解

本文地址:https://blog.csdn.net/huweiliyi/article/details/107692925