关于java:深度分析SpringAOP一文带你彻底搞懂SpringAOP底层原理

42次阅读

共计 5876 个字符,预计需要花费 15 分钟才能阅读完成。

SpringAOP

咱们为什么要应用 AOP(面向切面编程)?当咱们在事实中实现理论的我的项目时,咱们总是须要在一个“动作”进行前,进行中,或进行后进行一些操作,比方当咱们在运行程序时,咱们想要进行日志保留,或者在每一个办法调用后输入一句话,这就示意咱们每一次进行一个“动作”都须要进行同样的操作,这就导致程序员会进行大量的、无用的重复性动作,面对这种状况,AOP 应运而生。

AOP 概述

AOP,即 Aspect Oriented Rrogramming 的缩写,意为:面向切面编程,通过预编译形式和运行期间动静代理实现程序性能对立保护的一种技术。AOP 能够对业务漏极的各个局部进行隔离,从而使得业务逻辑之间得耦合性升高,进步程序得可重用性,同时进步了开发得效率。

AOP 和 OOP 是两种不同的设计思维。OOP(面向对象编程)针对业务处理过程得实体及其属性和行为进行形象封装,取得清晰高效得逻辑单元划分。AOP 则是针对业务处理过程中得切面进行提取,是面对业务处理过程中的某个步骤或阶段,取得逻辑过程中各局部之间低耦合性得隔离成果。

面向切面编程的益处就是:缩小反复,专一业务。它是面向对象编程的一种补充。
集体整顿了一些材料,有须要的敌人能够间接点击支付。

Java 基础知识大全

22 本 Java 架构师外围书籍

从 0 到 1Java 学习路线和材料

1000+ 道 2021 年最新面试题

外围原理及应用案例

原理:应用动静代理的形式在执行办法前后或出现异常时退出相干的逻辑。

应用:

事务处理:开启事务,敞开事务,出现异常回滚事务.....
权限判断:执行办法前,判断是否具备权限;日志解决;......
事务处理:开启事务,敞开事务,出现异常回滚事务.....
权限判断:执行办法前,判断是否具备权限;日志解决;......

AOP 的基本概念(Spring 的专业术语)

0. 加强:向各个程序外部注入一些逻辑代码从而加强原有程序的性能。

1. 连接点(JoinPoint):类中能够被加强的办法,这个办法就就被称为连接点,切记连接点并不是肯定会被加强。

2. 切入点(Pointcut):类中理论被加强的办法。

3. 告诉(Advice):指一个切面在特定的连接点要做的事件,简略来说就是“加强”。能够分为办法执行前告诉,办法执行后告诉,盘绕告诉等等。

4. 切面(Aspect):把告诉增加到切入点的过程就叫切面。

5. 指标(Target):代理的指标对象,即要加强的办法所在的类。

6. 代理(Proxy):向指标对象利用告诉之后创立的代理对象。

SpringAOP 实现

很多的框架都对 AOP 这种编程思维进行了实现。Spring 只是其中的一种,能够实现面向切面编程。AspectJ 也是一个面向切面的框架,并且实现形式更为简捷,更为不便,并且反对注解式开发。所以,Spring 又将 AspectJ 对于 AOP 的实现引入到本人的框架之中。

Spring 中应用 AOP 开发时,通常应用 AspectJ 的实现形式。其中罕用的告诉有五种类型:

  • 前置告诉:办法执行前执行;
  • 后置告诉:办法执行后执行;
  • 盘绕告诉:前后都执行;
  • 异样告诉:出异样时告诉;
  • 最终告诉:如 return 后执行。

SpringAOP 的应用

导入实现 AOP 的 AspectJ 的 jar

<!--Spring 实现 AOP 是依附 Aspects 框架实现 -->
<!--Aspects 相干 jar-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>

基于 AspectJ 的 xml 配置实现

所有的配置都在 spring.xml 文件中进行。

1. 创立一个加强性能的类。

import org.aspectj.lang.ProceedingJoinPoint;
// 告诉(Advice): 在连接点要做的事件
public class Aop {public void doLog() {System.out.println("===== 保留日志 =====");
    }

    public void commit() {System.out.println("===== 提交事务 =====");
    }

    public void around(ProceedingJoinPoint proceedingJoinPoint) {System.out.println("====== 办法前告诉 ======");
        try {proceedingJoinPoint.proceed();// 调用本人的办法
        } catch (Throwable throwable) {throwable.printStackTrace();
        }
        System.out.println("====== 办法后告诉 ======");
    }

    public void throwable(Throwable throwable) {System.out.println("====== 出异样了 ======");
        System.out.println(throwable.getMessage());
    }
}

2. 将装有加强性能的类交给交由 spring 治理

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 把装有告诉 (Advice) 的类交给 Spring 治理 -->
    <bean id="aop" class="com.cwd.spring4pro.demo1.aop.Aop"></bean>
    
    <!-- 在这里进行织入, 即切面(Aspect): 将告诉增加到切入点 -->

</beans>

3. 配置切面(Aspect)

先筹备一个被加强的类,即指标(Target)

import org.springframework.stereotype.Component;

// 指标(Target): 代理的指标对象,即要加强的类
@Component(value = "target")
public class Target {
    /*
    连接点(Joinpoint), 能够被加强的办法
    切入点(pointcut), 理论被加强的办法, 被加强了
    */
    public void pointCut() {System.out.println("这是一个保留的操作!!!");
        return;
    }
}

将告诉增加到切入点。

<!-- 织入 -->
    <aop:config>
        <!--
        配置切入点 
        execution 表达式 前 * 示意返回值 saveUser(..)示意要加强的办法 .. 示意参数
        -->
        
        <aop:pointcut id="pointCut" expression="execution(* com.cwd.spring4pro.demo.Target.pointCut(..))"/>

        <!-- 配置告诉 ref 中援用的是告诉类的 id-->
        <aop:aspect ref="aop">
        
           <!-- 前置告诉 -->
           <aop:before method="doLog" pointcut-ref="pointCut"/>

        </aop:aspect>
    </aop:config>

五种告诉类型配置

1. 前置告诉

<!-- 织入 -->
<aop:config>
    <aop:pointcut id="pointCut" expression="execution(* com.cwd.spring4pro.demo.Target.pointCut(..))"/>
    <aop:aspect ref="aop">
        <!-- 前置告诉 -->
        <aop:before method="doLog" pointcut-ref="pointCut"/>
    </aop:aspect>
</aop:config>

2. 后置告诉

<!-- 织入 -->
<aop:config>
    <aop:pointcut id="pointCut" expression="execution(* com.cwd.spring4pro.demo.Target.pointCut(..))"/>
    <aop:aspect ref="aop">
        <!-- 后置告诉 -->
        <aop:after method="commit" pointcut-ref="pointCut"/>
    </aop:aspect>
</aop:config>

3. 盘绕告诉

<!-- 织入 -->
<aop:config>
    <aop:pointcut id="pointCut" expression="execution(* com.cwd.spring4pro.demo.Target.pointCut(..))"/>
    <aop:aspect ref="aop">
        <!-- 盘绕告诉 -->
        <aop:around method="around" pointcut-ref="pointCut"/>
    </aop:aspect>
</aop:config>

4. 异样告诉

public void pointCut() {System.out.println("这是一个保留的操作!!!");
    int a = 10 / 0;
    return;
}
<!-- 织入 -->
<aop:config>
    <aop:pointcut id="pointCut" expression="execution(* com.cwd.spring4pro.demo.Target.pointCut(..))"/>
    <aop:aspect ref="aop">
        <!-- 异样告诉 -->
        <aop:after-throwing method="throwable" pointcut-ref="pointCut" throwing="throwable"/>
    </aop:aspect>
</aop:config>

5. 最终告诉

<!-- 织入 -->
<aop:config>
    <aop:pointcut id="pointCut" expression="execution(* com.cwd.spring4pro.demo.Target.pointCut(..))"/>
    <aop:aspect ref="aop">
        <!-- 最终告诉 -->
        <aop:after-returning method="commit" pointcut-ref="pointCut"/>
    </aop:aspect>
</aop:config>

最终告诉个别在 return 之后执行。

注解实现

开启 aop 注解扫描

<!-- 开启注解标签 -->
<aop:aspectj-autoproxy/>

在告诉类中进行配置,如下所示:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component// 将这个类交给 Spring 治理
@Aspect// 标注这个类时装有告诉的类
public class Aop {@Before("execution(* com.cwd.spring4pro.demo.Target.pointCut(..))")
    public void doLog() {System.out.println("===== 保留日志 =====");
    }

    @After("execution(* com.cwd.spring4pro.demo.Target.pointCut(..))")
    public void commit() {System.out.println("===== 提交事务 =====");
    }

    public void around(ProceedingJoinPoint proceedingJoinPoint) {System.out.println("====== 办法前告诉 ======");
        try {proceedingJoinPoint.proceed();// 调用本人的办法
        } catch (Throwable throwable) {throwable.printStackTrace();
        }
        System.out.println("====== 办法后告诉 ======");
    }


    @AfterThrowing(value = "execution(* com.cwd.spring4pro.demo.Target.pointCut(..))",throwing = "throwable")
    public void throwable(Throwable throwable) {System.out.println("====== 出异样了 ======");
        System.out.println(throwable.getMessage());
    }

    @AfterReturning("execution(* com.cwd.spring4pro.demo.Target.pointCut(..))")
    public  void returnAfter() {System.out.println("======return 后 =====");
    }
}

最初

都看到这里了,感觉文章对你有帮忙的话记得点个赞,感激反对!

正文完
 0