spring-aop

术语名词

1-横切关注点

从每个方法中抽取出来的同一类非核心业务。在同一个项目中,我们可以使用多个横切关注点对相关方法进行多个不同方面的增强。

这个概念不是语法层面天然存在的,而是根据附加功能的逻辑上的需要:有十个附加功能,就有十个横切关注点。AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事务、异常等。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

2-通知(增强)

每一个横切关注点上要做的事情都需要写一个方法来实现,这样的方法就叫通知方法。

- 前置通知:在被代理的目标方法前执行
- 返回通知:在被代理的目标方法成功结束后执行(**寿终正寝**)
- 异常通知:在被代理的目标方法异常结束后执行(**死于非命**)
- 后置通知:在被代理的目标方法最终结束后执行(**盖棺定论**)
- 环绕通知:使用try...catch...finally结构围绕整个被代理的目标方法,包括上面四种通知对应的所有位置

3-连接点 joinpoint

这也是一个纯逻辑概念,不是语法定义的。

指那些被拦截到的点。在 Spring 中,可以被动态代理拦截目标类的方法

4-切入点 pointcut

定位连接点的方式,或者可以理解成被选中的连接点!

是一个表达式,比如execution(* com.spring.service.impl.*.*(..))。符合条件的每个方法都是一个具体的连接点。

5-切面 aspect

切入点和通知的结合。是一个类。

6-目标 target

被代理的目标对象。

7-代理 proxy

向目标对象应用通知之后创建的代理对象。

8-织入 weave

指把通知应用到目标上,生成代理对象的过程。可以在编译期织入,也可以在运行期织入,Spring采用后者。

AOP思维,框架,技术相关

Spring-AOP的具体实现

依赖:

        <!-- spring-aspects会帮我们传递过来aspectjweaver -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>6.0.6</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>6.0.6</version>
        </dependency>

快速实现案例

1,定义增强类

package com.bubu.com.bubu.advice;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/*
 * 前置:@Before
 * 后置:@AfterReturning
 * 异常:@AfterThrowing
 * 最后:@After
 * 环绕:@Around
 * */
@Component
@Aspect   //切面注解,不加配置会全部生效
public class LogAdvice {
    @Before("execution(* com.bubu.service.Impl.*.*(..))")
    public void start(){
        System.out.println("方法开始了");
    }

    @After("execution(* com.bubu.service.Impl.*.*(..))")
    public void after(){
        System.out.println("方法结束了");
    }

    @AfterThrowing("execution(* com.bubu.service.Impl.*.*(..))")
    public void error(){
        System.out.println("方法报错了");
    }
}

2,在配置类中进行扫描:

@Configuration
@ComponentScan("com.bubu")
@EnableAspectJAutoProxy //开启aspectj的注解配置

获取切点详细信息

* 前置:@Before
* 后置:@AfterReturning
* 异常:@AfterThrowing
* 最后:@After
* 环绕:@Around

package com.bubu.com.bubu.advice;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MyAdvice {
    @Before("execution(* com..Impl.*.*(..))")
    public void before(JoinPoint joinPoint){
        //1,获取方法属于类的信息
        String simpleName = joinPoint.getTarget().getClass().getSimpleName();
        //2,获取方法名称
        joinPoint.getSignature().getName();
        //3,获取参数列表
        Object[] args = joinPoint.getArgs();//获取目标方法参数
        System.out.println("Before Advice");
    }

    @AfterReturning(value = "execution(* com..Impl.*.*(..))",returning = "result")
    public void afterReturning(JoinPoint joinPoint,Object result){
        System.out.println(result);
        System.out.println("After Returning Advice");

    }

    @After("execution(* com..Impl.*.*(..))")
    public void after(JoinPoint joinPoint){
        System.out.println("After Advice");
    }

    @AfterThrowing(value = "execution(* com..Impl.*.*(..))",throwing = "throwable")
    public void afterThrowing(JoinPoint joinPoint,Throwable throwable){
        System.out.println(throwable);
        System.out.println("After Throwing Advice");
    }
}

其中有关切点表达式:

对于切点表达式的提取和复用:

创建储存切点的类:

package com.bubu.pointcut;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MyPointCut {
    @Pointcut("execution(* com..Impl.*.*(..))")
    public void pC1() {}

    @Pointcut("execution(* com.bubu.service.Impl.*.*(..))")
    public void pC2() {}

}

通过调用切点类的全限定符:

public class LogAdvice {
    @Before("com.bubu.pointcut.MyPointCut.pC2()")
    public void start(){
        System.out.println("方法开始了");
    }

    @After("com.bubu.pointcut.MyPointCut.pC2()")
    public void after(){
        System.out.println("方法结束了");
    }

    @AfterThrowing("com.bubu.pointcut.MyPointCut.pC2()")
    public void error(){
        System.out.println("方法报错了");
    }
}

这样可以实现切点的统一管理

环绕通知

要求有一个返回值

package com.bubu.com.bubu.advice;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class TxAroundAdvice {
    /*
    * 环绕通知,需要在通知中定义目标方法的执行
    *
    * @param joinPoint 目标方法(获取目标方法信息,多了一个执行方法)
    * @return 目标方法的放回值
    * */

    @Around("com.bubu.pointcut.MyPointCut.pC1()")
    public Object around(ProceedingJoinPoint joinPoint){

        Object[] args = joinPoint.getArgs();
        Object result = null;
        try {
            //增强代码-》before
            System.out.println("开启事务");
            result = joinPoint.proceed(args);
            System.out.println("结束事务");
        }catch(Throwable e){
            System.out.println("事务回滚");
            throw new RuntimeException(e);
        }
        return result;
    }
}

切面优先级设定

@Order()

里边的数字越小,优先级越高。

使用xml文件的方式实现AOP的功能

<!-- 配置目标类的bean -->
<bean id="calculatorPure" class="com.atguigu.aop.imp.CalculatorPureImpl"/>
    
<!-- 配置切面类的bean -->
<bean id="logAspect" class="com.atguigu.aop.aspect.LogAspect"/>
    
<!-- 配置AOP -->
<aop:config>
    
    <!-- 配置切入点表达式 -->
    <aop:pointcut id="logPointCut" expression="execution(* *..*.*(..))"/>
    
    <!-- aop:aspect标签:配置切面 -->
    <!-- ref属性:关联切面类的bean -->
    <aop:aspect ref="logAspect">
        <!-- aop:before标签:配置前置通知 -->
        <!-- method属性:指定前置通知的方法名 -->
        <!-- pointcut-ref属性:引用切入点表达式 -->
        <aop:before method="printLogBeforeCore" pointcut-ref="logPointCut"/>
    
        <!-- aop:after-returning标签:配置返回通知 -->
        <!-- returning属性:指定通知方法中用来接收目标方法返回值的参数名 -->
        <aop:after-returning
                method="printLogAfterCoreSuccess"
                pointcut-ref="logPointCut"
                returning="targetMethodReturnValue"/>
    
        <!-- aop:after-throwing标签:配置异常通知 -->
        <!-- throwing属性:指定通知方法中用来接收目标方法抛出异常的异常对象的参数名 -->
        <aop:after-throwing
                method="printLogAfterCoreException"
                pointcut-ref="logPointCut"
                throwing="targetMethodException"/>
    
        <!-- aop:after标签:配置后置通知 -->
        <aop:after method="printLogCoreFinallyEnd" pointcut-ref="logPointCut"/>
    
        <!-- aop:around标签:配置环绕通知 -->
        <!--<aop:around method="……" pointcut-ref="logPointCut"/>-->
    </aop:aspect>
    
</aop:config>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值