spring之aop

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: spring之aop

介绍aop

Spring AOP 是 Spring 框架中的一个模块,它是基于面向切面编程 (AOP) 的一个实现。它可以让开发者在不改变原有代码的情况下,通过横向切面的方式,实现对系统的增强。Spring AOP 提供了很多常用的切面,如日志、事务、安全等,同时也支持自定义切面。Spring AOP 采用了动态代理的方式,在程序运行时才会生成代理对象,从而实现对目标对象的增强。


AOP 的全称是“Aspect Oriented Programming”,即面向切面编程,它将业务逻辑的各个部分进行隔离,使开发人员在编写业务逻辑时可以专心于核心业务,从而提高了开发效率。


AOP 采取横向抽取机制,取代了传统纵向继承体系的重复性代码,其应用主要体现在事务处理、日志管理、权限控制、异常处理等方面。


目前最流行的 AOP 框架有两个,分别为 Spring AOP 和 AspectJ。


Spring AOP 使用纯 Java 实现,不需要专门的编译过程和类加载器,在运行期间通过代理方式向目标类植入增强的代码。


AspectJ 是一个基于 Java 语言的 AOP 框架,从 Spring 2.0 开始,Spring AOP 引入了对 AspectJ 的支持。AspectJ 扩展了 Java 语言,提供了一个专门的编译器,在编译时提供横向代码的植入。

名称 说明
Joinpoint(连接点) 指那些被拦截到的点,在 Spring 中,可以被动态代理拦截目标类的方法。
Pointcut(切入点)

指要对哪些 Joinpoint 进行拦截,即被拦截的连接点。

Advice(通知) 指拦截到 Joinpoint 之后要做的事情,即对切入点增强的内容。
Target(目标)

指代理的目标对象。

Weaving(植入)

指把增强代码应用到目标上,生成代理对象的过程。

Proxy(代理)

指生成的代理对象。

Aspect(切面) 切入点和通知的结合。

 

AOP的概念和作用

AOP是一种编程范式,旨在解决横切关注点的代码重复问题。

AOP通过将横切关注点从主业务逻辑中分离出来,实现了更好的代码模块化和可维护性。

AOP可以在不改变原有代码的情况下,通过织入(Weaving)切面(Aspect)来实现对横切关注点的处理。

Spring AOP的基本原理和实现方式


Spring AOP基于动态代理(Dynamic Proxy)实现。

Spring AOP提供了两种代理方式:JDK动态代理和CGLIB代理。

JDK动态代理适用于基于接口的代理,而CGLIB代理适用于类级别的代理。

Spring AOP通过代理对象将切面织入到目标对象的方法调用中,实现对横切关注点的处理。

AOP中的主要概念

切面(Aspect):横切关注点的模块化单元,它包含了通知和切点。



连接点(Join Point):在程序执行过程中能够被切面织入的特定点。



切点(Pointcut):用于定义连接点的表达式,指定了哪些连接点将被切面织入。



通知(Advice):切面在连接点上执行的动作,包括前置通知、后置通知、异常通知、环绕通知和引入通知。



织入(Weaving):将切面应用到目标对象中的过程,可以在编译时、类加载时或运行时进行。


总结:Spring AOP通过代理和织入的方式,实现了对横切关注点的处理。它的基本原理是通过动态代理来生成代理对象,并将切面织入到目标对象的方法调用中。在AOP中,切面、连接点、切点、通知和织入是重要的概念,它们共同构成了Spring AOP的基本框架。


后置通知

   实现org.springframework.aop.AfterReturningAdvice接口

   买书返利(存在bug)


   环绕通知

   org.aopalliance.intercept.MethodInterceptor

   类似拦截器,会包括切入点,目标类前后都会执行代码。

 

   异常通知

   org.springframework.aop.ThrowsAdvice

   出现异常执行系统提示,然后进行处理。价格异常为例

 

   过滤通知(适配器)

   org.springframework.aop.support.RegexpMethodPointcutAdvisor

   处理买书返利的bug


Spring AOP的应用场景

日志记录:可以使用AOP拦截方法,记录方法的执行时间、参数、返回值等信息,实现日志的自动记录。


安全控制:可以使用AOP拦截访问操作,实现对用户访问权限的控制,例如检查用户是否有权限访问某些资源。


性能监控:可以使用AOP拦截方法,监控方法的执行时间、调用次数等信息,实现对系统性能的监控和优化。


缓存管理:可以使用AOP拦截方法,实现缓存管理,例如缓存对象的读取、写入、删除等操作。


事务管理:可以使用AOP拦截方法,实现事务管理,例如对数据库操作进行事务控制。


异常处理:可以使用AOP拦截方法,实现异常处理,例如捕获异常并记录日志或者发送通知。


优点:


1. 降低了代码的重复性:通过将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来,可以减少代码的重复性,提高代码的可维护性和可读性。


2. 提高了代码的模块化和可重用性:将横切关注点封装成切面,可以将其应用到多个目标对象中,提高了代码的模块化和可重用性。


3. 简化了业务逻辑的编写:通过使用切面,可以将与业务逻辑无关的代码(如事务管理、异常处理等)从业务逻辑中抽离出来,使业务逻辑更加清晰和简洁。


4. 提供了更好的代码结构和可扩展性:通过使用切面,可以将不同关注点的代码分离,使代码结构更加清晰,并且可以灵活地添加、修改或删除切面,以满足不同的需求。


缺点:


1. 仅支持方法级别的切面:Spring AOP只能对方法进行切面织入,对于其他级别的切面(如字段访问、对象创建等),需要使用其他的AOP框架。


2. 无法拦截私有方法和静态方法:由于Spring AOP基于动态代理实现,无法拦截私有方法和静态方法。


3. 对性能有一定的影响:由于Spring AOP使用动态代理来生成代理对象,并在方法调用时进行切面织入,会增加一定的性能开销。


4. 需要依赖Spring框架:使用Spring AOP需要依赖Spring框架,对于不使用Spring框架的项目来说,引入Spring框架可能会增加项目的复杂性。



前置通知

前置通知(Before advice):在目标方法执行前,执行的通知。可以用来在方法执行前进行一些准备或检查操作。


spring-context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       default-autowire="byType"
       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 class="com.aop.biz.impl.BookBizImpl" name="bookBiz"></bean>
<!--通知-->
    <bean class="com.aop.biz.advice.MyMethodBeforeAdvice" id="methodBeforeAdvice"></bean>
<!--代理-->
    <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="bookProxy">
<!--        配置目标对象-->
        <property name="target" ref="bookBiz"></property>
<!--        配置代理的接口-->
        <property name="proxyInterfaces">
            <list>
                <value>com.aop.biz.IBookBiz</value>
            </list>
        </property>
<!--配置通知-->
        <property name="interceptorNames">
            <list>
                <value>methodBeforeAdvice</value>
            </list>
        </property>
    </bean>
</beans>
package com.aop.biz.advice;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
 * 买书、评论前加系统日志
 * @author Administrator
 *
 */
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
//        在这里,可以获取到目标类的全路径及方法及方法参数,然后就可以将他们写到日志表里去
        String target = arg2.getClass().getName();
        String methodName = arg0.getName();
        String args = Arrays.toString(arg1);
        System.out.println("【前置通知:系统日志】:"+target+"."+methodName+"("+args+")被调用了");
    }
}

后置通知

后置通知(After advice):在目标方法执行后,执行的通知。可以用来在方法执行后进行一些清理操作,例如释放资源或记录执行结果。

package com.aop.biz.advice;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
 * 买书返利
 * @author Administrator
 *
 */
public class MyAfterReturningAdvice implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
        String target = arg3.getClass().getName();
        String methodName = arg1.getName();
        String args = Arrays.toString(arg2);
        System.out.println("【后置通知:买书返利】:"+target+"."+methodName+"("+args+")被调用了,"+"该方法被调用后的返回值为:"+arg0);
    }
}

环绕通知

环绕通知(Around advice):在目标方法执行前和执行后,执行的通知。可以用来在目标方法执行前后做一些预处理和后处理操作。

package com.zking.aop.advice;
import java.util.Arrays;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
 * 环绕通知
 *     包含了前置和后置通知
 * 
 * @author Administrator
 *
 */
public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation arg0) throws Throwable {
        String target = arg0.getThis().getClass().getName();
        String methodName = arg0.getMethod().getName();
        String args = Arrays.toString(arg0.getArguments());
        System.out.println("【环绕通知调用前:】:"+target+"."+methodName+"("+args+")被调用了");
//        arg0.proceed()就是目标对象的方法
        Object proceed = arg0.proceed();
        System.out.println("【环绕通知调用后:】:该方法被调用后的返回值为:"+proceed);
        return proceed;
    }
}

异常通知

异常通知(After throwing advice):在目标方法抛出异常时,执行的通知。可以用来做一些异常处理操作。

package com.aop.biz.advice;
import org.springframework.aop.ThrowsAdvice;
import com.aop.biz.Exception.PriceException;
/**
 * 出现异常执行系统提示,然后进行处理。价格异常为例
 * @author Administrator
 *
 */
public class MyThrowsAdvice implements ThrowsAdvice {
    public void afterThrowing(PriceException ex) {
        System.out.println("【异常通知】:当价格发生异常,那么执行此处代码块!!!");
    }
}

过滤通知

过滤通知(After returning advice):在目标方法执行成功并正常返回时,执行的通知。可以用来做一些返回结果的处理。

所有用到的bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       default-autowire="byType"
       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 class="com.aop.biz.impl.BookBizImpl" name="bookBiz"></bean>
<!--通知-->
    <bean class="com.aop.biz.advice.MyMethodBeforeAdvice" id="methodBeforeAdvice"></bean>
    <bean class="com.aop.biz.advice.MyAfterReturningAdvice" id="myAfterReturningAdvice"></bean>
    <bean class="com.aop.biz.advice.MyMethodInterceptor" id="myMethodInterceptor"></bean>
    <bean class="com.aop.biz.advice.MyThrowsAdvice" id="myThrowsAdvice"></bean>
    <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="regexpMethodPointcutAdvisor">
        <property name="advice" ref="myAfterReturningAdvice"></property>
        <property name="pattern" value=".*buy"></property>
    </bean>
<!--代理-->
    <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="bookProxy">
<!--        配置目标对象-->
        <property name="target" ref="bookBiz"></property>
<!--        配置代理的接口-->
        <property name="proxyInterfaces">
            <list>
                <value>com.aop.biz.IBookBiz</value>
            </list>
        </property>
<!--配置通知-->
        <property name="interceptorNames">
            <list>
                <value>methodBeforeAdvice</value>
<!--                <value>myAfterReturningAdvice</value>-->
                <value>regexpMethodPointcutAdvisor</value>
                <value>myMethodInterceptor</value>
                <value>myThrowsAdvice</value>
            </list>
        </property>
    </bean>
</beans>

总结:

Spring的AOP(面向切面编程)是通过动态代理实现的,它可以将横切关注点(如日志、事务、安全等)从业务逻辑中分离出来,以模块化的方式进行维护和复用,提高了程序的可维护性和扩展性。


在Spring中,AOP的实现主要依靠两个核心概念:切面和切点。切面是对一个或多个切点进行通知的模块化功能,它定义了在什么时候、在哪个地方、以何种方式进行通知,在Spring中,切面可以使用注解或XML配置来声明。切点是程序中用于插入切面的标记点,通过表达式或正则表达式定义,用于确定哪些方法需要被通知。


Spring的AOP通知包括前置通知、后置通知、返回通知、异常通知和环绕通知,每种通知都有不同的作用和执行顺序。为实现这些通知,Spring提供了不同的切面注解和方法,如@Before、@After、@AfterReturning、@AfterThrowing、@Around等。


总之,Spring的AOP是一种非常强大的编程范式,它可以在不修改业务代码的情况下,通过插入切面实现对程序行为的改变,提高程序的健壮性和可维护性。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
1月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
2月前
|
Java Spring
在Spring Boot中使用AOP实现日志切面
在Spring Boot中使用AOP实现日志切面
|
7天前
|
Java 数据库连接 数据库
Spring基础3——AOP,事务管理
AOP简介、入门案例、工作流程、切入点表达式、环绕通知、通知获取参数或返回值或异常、事务管理
Spring基础3——AOP,事务管理
|
1月前
|
XML Java 数据格式
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解
这篇文章是Spring5框架的AOP切面编程教程,通过XML配置方式,详细讲解了如何创建被增强类和增强类,如何在Spring配置文件中定义切入点和切面,以及如何将增强逻辑应用到具体方法上。文章通过具体的代码示例和测试结果,展示了使用XML配置实现AOP的过程,并强调了虽然注解开发更为便捷,但掌握XML配置也是非常重要的。
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解
|
20天前
|
缓存 Java 开发者
Spring高手之路22——AOP切面类的封装与解析
本篇文章深入解析了Spring AOP的工作机制,包括Advisor和TargetSource的构建与作用。通过详尽的源码分析和实际案例,帮助开发者全面理解AOP的核心技术,提升在实际项目中的应用能力。
18 0
Spring高手之路22——AOP切面类的封装与解析
|
1月前
|
安全 Java 开发者
Java 新手入门:Spring 两大利器IoC 和 AOP,小白也能轻松理解!
Java 新手入门:Spring 两大利器IoC 和 AOP,小白也能轻松理解!
29 1
|
1月前
|
Java Spring
Spring的AOP组件详解
该文章主要介绍了Spring AOP(面向切面编程)组件的实现原理,包括Spring AOP的基础概念、动态代理模式、AOP组件的实现以及Spring选择JDK动态代理或CGLIB动态代理的依据。
Spring的AOP组件详解
|
1月前
|
Java API Spring
Spring Boot 中的 AOP 处理
对 Spring Boot 中的切面 AOP 做了详细的讲解,主要介绍了 Spring Boot 中 AOP 的引入,常用注解的使用,参数的使用,以及常用 api 的介绍。AOP 在实际项目中很有用,对切面方法执行前后都可以根据具体的业务,做相应的预处理或者增强处理,同时也可以用作异常捕获处理,可以根据具体业务场景,合理去使用 AOP。
|
20天前
|
Java Spring XML
掌握面向切面编程的秘密武器:Spring AOP 让你的代码优雅转身,横切关注点再也不是难题!
【8月更文挑战第31天】面向切面编程(AOP)通过切面封装横切关注点,如日志记录、事务管理等,使业务逻辑更清晰。Spring AOP提供强大工具,无需在业务代码中硬编码这些功能。本文将深入探讨Spring AOP的概念、工作原理及实际应用,展示如何通过基于注解的配置创建切面,优化代码结构并提高可维护性。通过示例说明如何定义切面类、通知方法及其应用时机,实现方法调用前后的日志记录,展示AOP在分离关注点和添加新功能方面的优势。
30 0
|
29天前
|
缓存 安全 Java
Spring AOP 中两种代理类型的限制
【8月更文挑战第22天】
14 0