Spring AOP的概念与实现过程详解

 更新时间:2023年02月22日 08:29:28   作者:绿仔牛奶_  
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,可通过运行期动态代理实现程序功能的统一维护的一种技术。AOP是 Spring框架中的一个重要内容

Aop

什么是Aop?

AOP就是面向切面编程,通过预编译方式以及运行期间的动态代理技术来实现程序的统一维护功能。

什么是切面,我理解的切面就是两个方法之间,两个对象之间,两个模块之间就是一个切面。假设在两个模块之间需要共同执行一系列操作,并且最后将这一系列操作注入到两个模块之间的指定位置。此时这一系列操作就是切面,注入这些操作的位置称之为切点。

举例:公司员工上班

A员工上班需要在前台进行打卡,同样的B员工…其他员工都需要在前台打卡,那么如果为每一位员工提供单独的打卡通道就有些过于浪费资源。像这样

于是,在前台这个位置设置接口,声明公共的打卡方法,所有员工共同通过该接口进行打卡,那么在打卡时的一系列校验或者记录的整个操作就可以被称之为切面,前台这个空间位置就被称之为切点,如下图所示

aop主要作用就是进行日志记录、事务/异常处理等功能以便更好地维护开发,主要目的就是将这些行为从项目的业务逻辑代码中分离出来并且降低各个业务逻辑模块之间的耦合度。保证在执行aop操作的同时不会影响到项目的业务逻辑代码

几个概念

Aspect:切面 Aspect中会包含一些pointCut切入点以及一些Advice

Advice:通知 切面需要完成的工作,通过before、after、around来区别是在连接点之前或者之后 或者环绕

Target:目标 目标对象,该对象会被织入advice

PointCut:切点 即切面通知执行的地点 advice将会在这里发生

JointPoint:连接点 所有方法的执行点

PointCut用来修饰JointPoint,PointCut是advice执行的点,而JointPoint表示所有方法的执行点,通过PointCut可以确定哪些JointPoint是可以被织入的点

我们通常不希望advice会在所有的JointPoint点执行,PointCut的作用就是可以进行校验来更精准的匹配执行点。简单概括就是Jointpoint可以执行但未必执行,只有PointCut匹配到了JointPoint才可以在该点执行

Aspect切面可以理解为PointCut+Advice

使用AOP织入导入包

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.9.7</version>
  <scope>runtime</scope>
</dependency>

实现aop方式一

使用spring内置的API接口

准备:UserService、UserServiceImpl简单实现CRUD

在spring核心配置文件applicationContext.xml中配置aop:

<?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      https://www.springframework.org/schema/beans/spring-beans.xsd                     http://www.springframework.org/schema/aop                  https://www.springframework.org/schema/aop/spring-aop.xsd">
  <bean id="userServiceImpl" class="com.mount.service.UserServiceImpl"/>
  <bean id="log" class="com.mount.log.log"/>
  <bean id="afterLog" class="com.mount.log.AfterLog"/>
  <!--  配置AOP  -->
  <aop:config>
    <!-- 切入点 expression表达式  表示从哪里开始执行   -->
    <aop:pointcut id="pointcut" expression="execution(* com.mount.service.UserServiceImpl.*(..))"/>
    <!--      执行环绕增强  -->
    <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
    <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
  </aop:config>
</beans>

编写执行前后日志

// 执行前  实现spring内置接口MethodBeforeAdvice
public class log implements MethodBeforeAdvice {
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"执行了"+method.getName()+"方法");
    }
}
// 执行后 实现AfterReturningAdvice 
public class AfterLog implements AfterReturningAdvice {
  public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
    System.out.println(target.getClass().getName()+"调用了"+method.getName()+"方法"+"返回的结果为"+returnValue);
  }
}

测试:

@Test
public void test01(){
  ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  UserService bean = context.getBean("userServiceImpl", UserService.class);
  bean.insert();
}

实现aop方式二

使用自定义类,只需要在applicationContext.xml中重新配置aop,并且自己diy一个类即可,在配置时可以选择任一方法为前置日志或后置日志即可

<!--  配置AOP 方式二  -->
<bean id="diy" class="com.mount.diyLog.diyLogImpl"/>
<aop:config>
  <!--     自定义切面 ref引入的类   -->
  <aop:aspect ref="diy">
    <aop:pointcut id="pointcut" expression="execution(* com.mount.service.UserServiceImpl.*(..))"/>
    <aop:before method="before" pointcut-ref="pointcut"/>
    <aop:after method="after" pointcut-ref="pointcut"/>
  </aop:aspect>
</aop:config>

diylog类

public class diyLog {
  public void before(){
    System.out.println("===before方法执行===");
  }
  public void after(){
    System.out.println("===after方法执行===");
  }
}

注解实现aop

首先需要在applicationContext.xml文件中打开SpringAOP对注解的支持

<!-- SpringAop开启注解支持 -->
<aop:aspectj-autoproxy/>
<!-- 映射自定义注解实现log类 -->
<bean id="annoLog" class="com.mount.annoLog.annoLogImpl"/>

annoLog

// Aspect标注该类是一个切面
@Aspect
public class annoLogImpl {
  // 前置增强
  @Before("execution(* com.mount.service.UserServiceImpl.*(..))")
  public void before(){
    System.out.println("---方法执行前---");
  }
  // 后置增强
  @After("execution(* com.mount.service.UserServiceImpl.*(..))")
  public void after(){
    System.out.println("---方法执行后---");
  }
  // 环绕增强
  @Around("execution(* com.yuqu.dao.UserMapperImpl.*(..))")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕前");
        Object proceed = pjp.proceed();
        System.out.println("环绕后");
        System.out.println("执行信息:"+pjp.getSignature());
        return proceed;
    }
}

最终打印:

环绕前
---方法执行前---
删除成功!
---方法执行后---
方法签名Integer com.mount.service.UserService.delete()
方法执行返回=1
环绕后

注意around环绕增强,如果我们执行的sql中是有返回值的话,那么必须显式的将pjp.proceed();返回回去,否则在调用处将会无法获取到结果集,报空指针异常

可以发现,around环绕增强首先执行,在执行到joinPoint.proceed()时,会执行对应方法,执行对应方法的时候才会执行前置或后置的其他增强操作

到此这篇关于Spring AOP的概念与实现过程详解的文章就介绍到这了,更多相关Spring AOP概念内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • IntelliJ IDEA中ajax开发实现分页查询示例

    IntelliJ IDEA中ajax开发实现分页查询示例

    这篇文章主要介绍了IntelliJ IDEA中ajax开发实现分页查询,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03
  • SpringBoot返回html界面的使用示例

    SpringBoot返回html界面的使用示例

    本文主要介绍了SpringBoot返回html界面的使用示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-11-11
  • Shiro在springboot中快速实现方法

    Shiro在springboot中快速实现方法

    Apache Shiro是一个Java的安全(权限)框架,可以容易的开发出足够好的应用,既可以在JavaEE中使用,也可以在JavaSE中使用,这篇文章主要介绍了Shiro在springboot中快速实现,需要的朋友可以参考下
    2023-02-02
  • idea自动加载html、js而无需重启进程的操作

    idea自动加载html、js而无需重启进程的操作

    这篇文章主要介绍了idea自动加载html、js而无需重启进程的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • java实现文件上传和下载

    java实现文件上传和下载

    这篇文章主要为大家详细介绍了java实现文件上传和下载,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-10-10
  • Java_异常类(错误和异常,两者的区别介绍)

    Java_异常类(错误和异常,两者的区别介绍)

    下面小编就为大家带来一篇Java_异常类(错误和异常,两者的区别介绍) 。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-09-09
  • 为Java应用创建Docker镜像的3种方式总结

    为Java应用创建Docker镜像的3种方式总结

    Docker的使用可以将应用程序做成镜像,这样可以将镜像发布到私有或者公有仓库中,在其他主机上也可以pull镜像,并且运行容器,运行程,下面这篇文章主要给大家总结介绍了关于为Java应用创建Docker镜像的3种方式,需要的朋友可以参考下
    2023-06-06
  • 简单了解springboot eureka交流机制

    简单了解springboot eureka交流机制

    这篇文章主要介绍了简单了解springboot eureka交流机制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • Spring Boot 使用 logback、logstash、ELK 记录日志文件的方法

    Spring Boot 使用 logback、logstash、ELK 记录日志文件的方法

    这篇文章主要介绍了Spring Boot 使用 logback、logstash、ELK 记录日志文件的思路详解,文中给大家提到了logback 取代 log4j的理由,需要的朋友可以参考下
    2017-12-12
  • java小程序之控制台字符动画的实现

    java小程序之控制台字符动画的实现

    这篇文章主要给大家介绍了java小程序之控制台字符动画实现的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04

最新评论