Spring--(4)AOP

本文介绍了面向切面编程(AOP),它是对面向对象编程(OOP)的补充,采用横向抽取机制解决OOP处理日志记录等操作的问题。还阐述了AOP术语、通知类型、动态代理(JDK和CGLIB),并详细说明了基于XML配置和注解开发AspectJ的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

AOP(Aspect-Ocriented Programming) 面向切口编程,它与 OOP (Object-Oriented Programming 面向对象编程) 相辅相成,提供了 与OOP 不同的抽象软件结构的视角

由来:
因为采用 OOP 处理日志记录等操作不仅增加了开发者的工作量,而且提高了升级维护的困难。为了解决此类问题,AOP思想应运而生。
AOP采取横向抽取机制,即将分散在各个方法中的重复代码提取出来,然后在程序编译或运行阶段将这些抽取出来的代码应用到需要执行的地方。
这种横向抽取机制采用传统的OOP是无法办到的,因为OOP实现了是父子关系的纵向重用
AOP不是OOP的替代品,而是OOP的补充,它们相辅相成

AOP术语在这里插入图片描述

通知类型

在这里插入图片描述

动态代理

在这里插入图片描述

JDK动态代理

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

CGLIB动态代理

在这里插入图片描述

使用 ProxyFactoryBean 创建代理

在这里插入图片描述
#在这里插入图片描述

开发 AspectJ

在这里插入图片描述

基于XML配置开发 AspectJ

依赖 jar
spring-aspects-5.0.2.RELEASE.jar
aspectjweaver-1.8.13.jar 是AspectJ 框架提供的规范包
可以去 maven Repository 官网下载

元素名称用途
<aop:config>在配置文件<beans>可以包含多个该元素
开发AspectJ的顶层配置元素
<aop:aspect><aop:config>的子元素
配置(定义一个切面)
属性 ref 指定切面的定义
<aop:pointcut><aop:aspect> 的子元素
配置切入点
属性expression 指定通知增强哪些方法
aop:before<aop:aspect>的子元素
配置前置通知
属性method 指定前置通知方法
属性 pointcut-ref 指定关联的切入点
<aop:after-returning><aop:aspect>的子元素
配置后置返回通知
属性method 指定后置返回通知
属性pintcut-ref 指定关联的切入点
<aop:around><aop:aspect>的子元素
配置环绕通知
属性method 指定环绕通知方法
属性pintcut-ref 指定关联的切入点
<aop:after-throwing><aop:aspect>的子元素
配置异常通知
属性method 指定异常通知方法
属性pintcut-ref 指定关联的切入点,没有 异常发生时将不会执行
<aop:after><aop:aspect>的子元素
配置后置(最终)通知
属性method 指定后置最终通知方法
属性pintcut-ref 指定关联的切入点
<aop:declare-parents>给通知引入新的额外接口,增强功能
<aop:config>
	<aop:aspect ref=""> </aop:aspect>
		<aop:point expression=""> </aop:point>
		<aop:before method="" pointcut-ref=""></aop:before>
		<aop:after-returning method="" pointcut-ref=""></aop:after-returning>
		<aop:around method="" pointcut-ref=""></aop:around>
		<aop:after-throwing method="" pointcut-ref=""></aop:after-throwing>
		<aop:after method="" pointcut-ref=""></aop:after>
</aop:config>
package aspectj.xml;
/*切面类,在此类中编写各种类型的通知*/
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class MyAspect {
    /*前置通知,使用JoinPoint接口作为参数获取目标对象信息*/
    public void before(JoinPoint js){
        System.out.println("前置通知,模拟权限控制");
        System.out.println("目标对象: " + js.getTarget() + ",被增强处理的方法: " + js.getSignature().getName());
    }
    /*后置返回通知*/
    public void afterReturning(JoinPoint js){
        System.out.println("后置返回通知,模拟删除临时文件");
        System.out.println("目标对象: " + js.getTarget() + ",被增强处理的方法: " + js.getSignature().getName());
    }
    /*环绕通知
    * ProceedingJoinPoint 是JoinPoint的子接口,代表可以执行的目标方法
    * 返回的类型必须是 Object
    * 必须一个参数是 ProceedingJoinPoint 类型
    * 必须 throws Throwable
    * */
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕开始:执行目标方法前,模拟开启事务");
        Object obj = pjp.proceed();
        System.out.println("环绕结束:执行目标方法后,模拟关闭事务");
        return obj;
    }
    /*异常通知*/
    public void except(Throwable e){
        System.out.println("异常通知: " + "程序执行异常 " + e.getMessage());
    }
    /*后置(最终)通知*/
    public void after(){
        System.out.println("最终通知:模拟释放资源");
    }
}

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="testDao" class="dynamic.jdk.TestDaoImpl"/>
    <!--定义切面-->
    <bean id="myAspect" class="aspectj.xml.MyAspect"/>
    <!--AOP配置-->
    <aop:config>
        <!--配置切面-->
        <aop:aspect ref="myAspect">
            <!--配置切入点,通知增强哪些方法-->
            <aop:pointcut id="myPointCut" expression="execution(* dynamic.jdk.*.*(..))"/>
            <!--将通知与切入点关联-->
            <!--关联前置通知-->
            <aop:before method="before" pointcut-ref="myPointCut"/>
            <!--关联后置返回通知,在目标方法成功后执行-->
            <aop:after-returning method="afterReturning" pointcut-ref="myPointCut"/>
            <!--关联环绕通知-->
            <aop:around method="around" pointcut-ref="myPointCut"/>
            <!--关联异常通知,没有异常发生时将不会执行增强,throwing属性设置通知的第二个参数名称-->
            <aop:after-throwing method="except" pointcut-ref="myPointCut" throwing="e"/>
            <!--关联后置(最终)通知,不管目标方法是否成功都要执行-->
            <aop:after method="after" pointcut-ref="myPointCut"/>
        </aop:aspect>
    </aop:config>
</beans>

expression="execution(* dynamic.jdk.*.*(..))"
是定义切入点表达式
意思:是匹配 dynamic.jdk 包中任意方法的执行
第一个 * 表示的是返回类型,使用 * 代表所有类型
第二个 * 表示的是类名,使用 * 代表匹配包中所有类
第三个 * 表示的是方法,使用 * 表示所有方法
(…) 表示方法的参数,其中 … 表示任意参数

package aspectj.xml.test;

import dynamic.jdk.TestDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class XMLAspectJTest {
    public static void main(String[] args) {
        ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
        TestDao testDaoAdvice = (TestDao) appCon.getBean("testDao");
        testDaoAdvice.save();
    }
}

在这里插入图片描述

基于注解开发 AspectJ

注解名称描述
@Aspect用于定义一个切面,注解在切面类上
@Pointcut用于定义切入点表达式,在使用时需要定义一个切入点方法
该方法是一个返回值 void 且方法体为空的普通方法
@Before用于定义前置通知
在使用时通常为其指定 value 属性值,该值可以是已有的切入点,也可以直接定义切入点表达式
@AfterReturning用于定义后置返回通知
在使用时通常为其指定 value 属性值,该值可以是已有的切入点,也可以直接定义切入点表达式
@Around用于定义环绕通知
在使用时通常为其指定 value 属性值,该值可以是已有的切入点,也可以直接定义切入点表达式
@AfterThrowing用于定义异常通知
在使用时通常为其指定 value 属性值,该值可以是已有的切入点,也可以直接定义切入点表达式
另外,还有一个 throwing 属性用于访问目标方法抛出的异常,该属性值与异常通知方法中同名的形参一致
@After用于定义后置(最终)通知
在使用时通常为其指定 value属性值,该值可以是已有的切入点,也可以直接定义切入点表达式

在这里插入图片描述
@Repository() 将目标类标识为bean
context:component-scan base-package="" 扫描需要的包,使注解生效
<aop:aspect-autoproxy/> 启动基于注解的AspectJ支持

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值