Spring Aop的理解都个人看法

什么是AOP

AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。

利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

在实际的开发场景中,很多业务涉及到相同的代码逻辑,就比如数据库连接这个业务过程就涉及到:获取连接、执行sql、关闭连接等三个最基本的逻辑,其中最核心的逻辑为执行sql,且根据sql的不同执行的逻辑也不一样,而获取连接和关闭连接则相反,在很多使用的地方都相同且非核心的逻辑,所以我们就可以将这两个部分单独抽离出来,通过类似动态注入的方式,在代码运行执行sql时动态的根据注入点获取这两个的代码逻辑并将它们组合在一起构成一个完整的业务逻辑,从而达到和抽离前一样的效果,同时也使代码间的耦合度大大降低。

AOP使用中涉及的知识点

1、连接点(Joinpoint)

程序在运行过程中能够织入抽离逻辑(切面)的地点,在spring中只要是方法都可以称之为连接点,例如,上面的执行sql的逻辑方法就是连接点、因为spring只支持方法级的连接点。

2、切入点(Pointcut)

 程序在运行过程中被织入抽离逻辑的方法,在我们开发的项目中,我们会写很多方法,这些   方法都能够织入抽离逻辑,所以他们都是连接点。但并不是所有的方法都会织入抽离逻辑,而那些被我们选择要织入抽离逻辑的方法则被称为切入点。

3、增强(Advice)

是切面(抽离逻辑)的具体实现。以上面的数据库连接的例子来说,获取连接逻辑、关闭连接逻辑都是增强,从字面理解就是对原有切点的增强。以目标方法为参照点,根据放置的地方不同,可分为前置通知(Before)、后置通知(AfterReturning)、异常通知(AfterThrowing)、最终通知(After)与环绕通知(Around)5种。在实际应用中通常是切面类中的一个方法,具体属于哪类通知,同样是在配置中指定的。

4、切面(Aspect)

其实就是上面我们将的抽离逻辑,下面我们分析一下切面的组成,前面我们知道了,连接点、切入点、增强三个概念,通过增强(Advice)我们知道每一个具体的抽离逻辑都是一个增强,同时为了让Advice能够正确的找到需要被增强的地方,所以我们必定要通过切入点来告知Advice要去哪里进行增强。通过这样一分析,我们不难发现切面是由切入点增强构成。

5、目标对象(Target)

就是那些即将(为什么说即将呢?因为织入是发生在Java运行过程中动态进行的)织入切面的目标类,用上面的数据库连接例子来说就是 执行sql 这个方法所在的类。

6、代理对象(Proxy)

将增强应用到目标对象之后被动态创建出的对象。可以简单地理解为,代理对象的功能等于目标对象的核心业务逻辑功能加上切面功能。代理对象对于使用者而言是不可见的,因为它是程序运行过程中的产物。

7、织入(Weaving)

将切面应用到目标对象从而创建一个新的代理对象的过程,我的理解是这个过程发生在jvm运行过程中。

//自定义注解

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAop {

}


//目标类
@TestAop
public void run(ApplicationArguments args) throws Exception {
   logger.info("[run]获取user数据源:{}",userDataSource.getClass());
   logger.info("[run]获取admin数据源:{}",adminDataSource.getClass());
}



//切面类

@Aspect
@Component
public class TestAopImpl {

    // 通过注解确定切入点位置
    @Pointcut(value = "@annotation(TestAop)")
    public void pointCut(){
    }

    // 前置增强
    @Before(value = "pointCut()")
    public void before(){
        System.out.println("前置增强,业务开始前执行");
    }

    //后置增强
    @After(value = "pointCut()")
    public void after(){
        System.out.println("后置增强,业务执行完后执行");
    }


    // 通过路径确定切入点
    @Pointcut(value = "execution(public * com.example.datasource.DruidApplication.run(..))")
    public void pointCut1(){
    }

    
    //环绕增强
    @Around(value = "pointCut1()")
    public void round(){
        System.out.println("-----环绕开始-----");
        System.out.println("环绕增强,开始环绕增强啦");
        System.out.println("-----环绕结束-----");
    }
}

 在@Around环绕通知的方法的参数中,我们可以传入JoinPoint或者ProceedingJoinPoint作为参数,其中ProceedingJoinPoint继承JoinPoint,JoinPoint接口中定义了获取连接点相关信息的一些方法,例如,连接点所在类信息、连接点方法名、连接点方法参数等等;ProceedingJoinPoint在JoinPoint的基础上增加了执行连接点方法的功能,该方法的作用是使环绕通知的前置和后置又较好的间隔区分。参考如下:

    @Pointcut(value = "@annotation(com.example.datasource.annotation.TestAop)")
    public void pointCut2(){
    }
    
    @Around(value = "pointCut2()")
    public Object round(ProceedingJoinPoint pjp) throws Throwable {
        String name = pjp.getTarget().getClass().getName();
        String method = pjp.getSignature().getName();
        System.out.println("-----环绕开始,目标类为"+name);
        Object proceed = pjp.proceed();
        System.out.println("-----环绕结束"+method);
        System.out.println("proceed参数"+proceed);
        return proceed;
    }


    @Override
    @TestAop
    public void run(ApplicationArguments args) throws Exception {
        logger.info("[run]获取user数据源:{}",userDataSource.getClass());
        logger.info("[run]获取admin数据源:{}",adminDataSource.getClass());
        String[] sourceArgs = args.getSourceArgs();
        System.out.println("打印命令行参数"+sourceArgs[0]);
    }

如果不加Object proceed = pjp.proceed();执行效果如下:

 从打印的信息来看我们很难区分前置增强和后置增强的界限。

 加了之后:

 可以看到加了proceed方法之后,该方法会调用一次切点目标方法,从而使得前置增强和后置增强有了一道间隔区分,该方法执行之前为前置增强,之后为后置增强。

                

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

龙茶清欢

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

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

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

打赏作者

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

抵扣说明:

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

余额充值