spring的aop

AOP(面向切面编程)是对OOP的补充,它用于将分散在各处的交叉关注点(如日志、事务管理等)进行模块化。AOP通过动态代理实现在运行时对方法的拦截,包括JDK动态代理和Cglib代理。主要概念包括目标对象、代理对象、连接点、切入点、通知和切面。通知分为前置、后置、环绕、异常和最终通知,切点表达式用于定义增强的执行时机。AOP的配置可以通过XML或注解方式实现。

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

aop

aop,面向切面编程。面向对象编程时对一个对象进行抽象。而面向切面编程时对不同的事物进行抽象,例如将不同的类中的方法都统一提出来,集中对这些方法进行操作。

aop实现原理

aop的底层是通过一个BeanDefinition注册一个AspectJAwareAdvisorAutoProxyCreator的bean,这个bean是个BeanPostProcess后处理器,而就是这个后处理器内部会调用aop封装的动态代理方法,底层有两个方法,分别是JDK和Cglib。
而注解方法和XML配置方式的底层都是相同,就是进入底层代码是调用的接口不同。

aop的基本概念

名词解释
Target(目标对象)被增强的方法的对象
Proxy( 代理对象)对目标对象进行增强后的对象
Joinpoint(连接点)目标对象中可以被增强的方法
Pointcut(切入点)目标对象中实际被增强的方法
Advice(通知\增强)增强部分的代码逻辑
Aspect(切面)增强和切入点的结合
Weaving(织入)将通知和切入点动态结合的过程

aop的五种通知

通知名称执行时机
前置通知目标方法执行之前执行
后置通知目标方法执行之后执行,当方法异常时,不执行
环绕通知目标方法前后执行,方法异常时,后环绕方法不执行
异常通知目标方法抛出异常时执行
最终通知目标方法无论是否有异常,最后都会执行

aop的切点表达式的配置

aop的两种切面配置方式

execution([访问修饰符] 返回的类型 包名.类名.方法名(参数))

当然在配置表达式时可以使用通配符

// .. 表示任意的参数
execution([访问修饰符] 返回的类型 包名.类名.方法名(..))


// * 表示任意类或方法
execution([访问修饰符] 返回的类型 包名.*.*(..))

// 包名和类名之间使用双点表示该包极其子包下的类
execution([访问修饰符] 返回的类型 包名..*.*(..))

aspect进行配置

xml标签配置

<aop:config>
        <!--配置切点表达式-->
        <aop:pointcut id="myPointcut" expression="execution(void com.service.impl.UserServiceImpl.show1())"/>
        <aop:pointcut id="myPointcut3" expression="execution(void com.service.impl.UserServiceImpl.show2())"/>
        <aop:pointcut id="myPointcut4" expression="execution(void com.service.impl.UserServiceImpl.show3())"/>
        <!--使用通配符进行配置-->
        <aop:pointcut id="myPointcut2" expression="execution(void com.service.impl.*.*(..))"/>
        <!--配置织入,将切点和通知相结合-->
        <!--aspect标签-->
        <aop:aspect ref="myAdvice">
            <!--前置方法-->
            <aop:before method="beforeAdvice" pointcut-ref="myPointcut"/>
            <!--普通后置方法-->
            <aop:after method="afterReturningAdvice" pointcut-ref="myPointcut"/>
            <!--强制执行后置方法-->
            <aop:after-returning method="afterAdvice" pointcut-ref="myPointcut" />
            <!--环绕方法-->
            <aop:around method="around" pointcut-ref="myPointcut"/>
            <!--只有有异常是才执行-->
            <aop:after-throwing method="afterThrowing" throwing="e" pointcut-ref="myPointcut"/>
        </aop:aspect>
    </aop:config>

通知类配置

public class MyAdvice {

    public void beforeAdvice(JoinPoint joinPoint){
        System.out.println("当前对象是:"+joinPoint.getTarget());
        System.out.println("当前对象的表达式:"+joinPoint.getStaticPart());
        System.out.println("前置方法.....");
    }

    public void afterAdvice(){
        System.out.println("最终方法.....");
    }

    public void afterReturningAdvice(){
        System.out.println("后置方法.....");
    }

    public Object around(ProceedingJoinPoint joinPoint){
        try {
            System.out.println("前置环绕方法执行.....");
            Object proceed = joinPoint.proceed();
            System.out.println("后置环绕方法执行.....");
            return proceed;
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }

    public void afterThrowing(Throwable e){
        System.out.println("当前的异常的信息为:"+e);
    }

}

当然这里的方法名只要一一对应就行,实际上想取什么名字都可以,但是一般还是取一些固定的名字,方便说明。

advisor配置

Xml配置

<aop:config>
        <!--配置切点表达式-->
        <aop:pointcut id="myPointcut" expression="execution(void com.service.impl.UserServiceImpl.show1())"/>
        <aop:pointcut id="myPointcut3" expression="execution(void com.service.impl.UserServiceImpl.show2())"/>
        <aop:pointcut id="myPointcut4" expression="execution(void com.service.impl.UserServiceImpl.show3())"/>
        <!--使用通配符进行配置-->
        <aop:pointcut id="myPointcut2" expression="execution(void com.service.impl.*.*(..))"/>

        <!--advisor标签-->
        <aop:advisor advice-ref="myAdvice2" pointcut-ref="myPointcut3"/>
        <aop:advisor advice-ref="myAdvice3" pointcut-ref="myPointcut4"/>
    </aop:config>

通知类配置

public class MyAdvice2 implements MethodBeforeAdvice, AfterReturningAdvice {


    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("接口实现的后置方法");
    }

    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("接口实现的后置方法");
    }
}
public class MyAdvice3 implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {

        System.out.println("接口环绕前置方法执行");
        Object result = methodInvocation.getMethod().invoke(methodInvocation.getThis(), methodInvocation.getArguments());
        System.out.println("接口环绕后置方法执行");
        return result;
    }
}

这中方式需要我们的通知类实现对应的接口,之后重写我们的接口方法。于是,在XML配置中就不需要指定我们的方法了。

Aop注解方式

要想使用注解,我们需要在我们的XML配置配置一下标签

<!--开启AOP自动代理-->
    <aop:aspectj-autoproxy/>

如果使用的的时配置类的话,需要加上@EnableAspectJAutoProxy标签

@Configuration
@ComponentScan("com")
@EnableAspectJAutoProxy
public class SpringConfig {
}

之后只需要在我们的通知类中加一个@Aspect标签,为每一个标签配置一下方法标签就可以了。

@Component
@Aspect
public class MyAdvice {


//配置切点
    @Pointcut("execution(void com.service.impl.UserServiceImpl.show2())")
    public void pointcut(){}


    @Before("MyAdvice.pointcut()")
    public void beforeAdvice(JoinPoint joinPoint){
        System.out.println("当前对象是:"+joinPoint.getTarget());
        System.out.println("当前对象的表达式:"+joinPoint.getStaticPart());
        System.out.println("前置方法.....");
    }

    @AfterReturning("MyAdvice.pointcut()")
    public void afterAdvice(){
        System.out.println("最终方法.....");
    }


    @After("MyAdvice.pointcut()")
    public void afterReturningAdvice(){
        System.out.println("后置方法.....");
    }

    @Around("MyAdvice.pointcut()")
    public Object around(ProceedingJoinPoint joinPoint){
        try {
            System.out.println("前置环绕方法执行.....");
            Object proceed = joinPoint.proceed();
            System.out.println("后置环绕方法执行.....");
            return proceed;
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }

    @AfterThrowing(pointcut = "MyAdvice.pointcut()",throwing = "e")
    public void afterThrowing(Throwable e){
        System.out.println("当前的异常的信息为:"+e);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风过于前

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值