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

目录
  • Aop
  • 实现aop方式一
  • 实现aop方式二
  • 注解实现aop

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概念内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Spring AOP如何自定义注解实现审计或日志记录(完整代码)

    目录 环境准备 项目结构 自定义审计注解 定义切面类 定义返回值处理基类 定义返回值处理子类 定义功能模块类 定义操作类 定义审计信息实体类 书写mapper文件 开启AOP拦截 注解配置 总结 环境准备 JDK 1.8,Springboot 2.1.3.RELEASE,spring-boot-starter-aop.2.1.4.RELEASE.jar,aspectjrt.1.9.2.jar,aspectjweaver.1.9.2.jar,pom依赖如下: <!-- 添加aspectj -->

  • SpringBoot使用AOP与注解实现请求参数自动填充流程详解

    首先定义一个加在方法上的注解 import java.lang.annotation.*; /** * 开启自动参数填充 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) @Documented @Inherited public @interface AutoParameterFill { /** * 要填充的字段名,不写的话默认下面类的子类中的字段都要填充 * * @see AutoParameterFi

  • Spring使用AOP完成统一结果封装实例demo

    目录 Spring使用AOP完成统一结果封装 Demo实现 Spring使用AOP完成统一结果封装 起因:自己写项目的时候忍受不了每个方法都要写一个retrun Result.success();和 retrun Result.error();,同时想到项目运行时异常的统一捕捉处理,于是我就在想有没有一种方法能够快捷有效的实现统一返回结果格式的方法.同时也能够比较方便的设置各种参数方便使用,于是我就想到AOP. Demo实现 引入依赖 <dependency> <groupId>o

  • Spring AOP实现声明式事务机制源码解析

    目录 一.声明式全局事务 二.源码 三.小结: 一.声明式全局事务 在Seata示例工程中,能看到@GlobalTransactional,如下方法示例: @GlobalTransactional public boolean purchase(long accountId, long stockId, long quantity) { String xid = RootContext.getXID(); LOGGER.info("New Transaction Begins: " +

  • Spring AOP统一功能处理示例代码

    目录 1. 什么是Spring AOP? 2. 为什要用 AOP? 3. Spring AOP 应该怎么学习呢? 3.1AOP组成 3.1.1 切面(Aspect) 3.1.2 连接点(Join Point) 3.1.3 切点(Pointcut) 3.1.4 通知(Advice) 3.2 Spring AOP实现 3.2.1 添加 AOP 框架支持 3.2.2 定义切面和切点. 3.2.3 定义相关通知 3.3 Spring AOP 实现原理 3.3.1 动态代理 3.3.2 JDK和CGLIB

  • Spring AOP源码深入分析

    目录 1. 前言 2. 术语 3. 示例 4. @EnableAspectJAutoProxy 5. AbstractAutoProxyCreator 6. 构建Advisor 7. 创建代理对象 8. DynamicAdvisedInterceptor 9. CglibMethodInvocation 10. Advice子类 1. 前言 Spring除了IOC和DI,还有另一个杀手锏功能——Spring AOP.AOP是一种面向切面的编程思想,它的关注点是横向的,不同于OOP的纵向.面向对象

  • Spring AOP与AspectJ的对比及应用详解

    目录 1 简介 2 Spring AOP vs AspectJ 2.1 织入方式 2.2 Joinpoints 2.3 性能 3 Spring Boot使用AspectJ 3.1 引入依赖 3.2 被AOP的对象 3.3 配置Aspect 3.4 maven插件 3.5 执行及测试 3.6 一些遇到的错误 4 总结 1 简介 AOP,即面向切面编程是很常用的技术,特别是在Java Web开发中.而最流行的AOP框架分别是Spring AOP和AspectJ. 2 Spring AOP vs As

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

    目录 Aop 实现aop方式一 实现aop方式二 注解实现aop Aop 什么是Aop? AOP就是面向切面编程,通过预编译方式以及运行期间的动态代理技术来实现程序的统一维护功能. 什么是切面,我理解的切面就是两个方法之间,两个对象之间,两个模块之间就是一个切面.假设在两个模块之间需要共同执行一系列操作,并且最后将这一系列操作注入到两个模块之间的指定位置.此时这一系列操作就是切面,注入这些操作的位置称之为切点. 举例:公司员工上班 A员工上班需要在前台进行打卡,同样的B员工…其他员工都需要在前台

  • Spring框架实现AOP添加日志记录功能过程详解

    这篇文章主要介绍了Spring框架实现AOP添加日志记录功能过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 需求,在调用业务方法的时候,在被调用的业务方法的前面和后面添加上日志记录功能 整体架构: 日志处理类: package aop; import java.util.Arrays; import org.apache.log4j.Logger; import org.aspectj.lang.JoinPoint; //日志处理类 增

  • Spring AOP 动态多数据源的实例详解

     Spring AOP 动态多数据源的实例详解 当项目中使用到读写分离的时候,我们就会遇到多数据源的问题.多数据源让人最头痛的,不是配置多个数据源,而是如何能灵活动态的切换数据源.例如在一个spring和Mybatis的框架的项目中,我们在spring配置中往往是配置一个dataSource来连接数据库,然后绑定给sessionFactory,在dao层代码中再指定sessionFactory来进行数据库操作. 正如上图所示,每一块都是指定绑死的,如果是多个数据源,也只能是下图中那种方式. 可看

  • Spring基于xml文件配置Bean过程详解

    这篇文章主要介绍了spring基于xml文件配置Bean过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 通过全类名来配置: class:bean的全类名,通过反射的方式在IOC容器中创建Bean,所以要求bean中必须有一个无参的构造器. <bean id="helloWorld" class="com.gong.spring.beans.HelloWorld"> <property na

  • Spring AOP定义Before增加实战案例详解

    本文实例讲述了Spring AOP定义Before增加.分享给大家供大家参考,具体如下: 一 配置 <?xml version="1.0" encoding="GBK"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:

  • Spring Aop常见注解与执行顺序详解

    目录 Spring Aop 的常用注解 常见问题 示例代码 配置文件 接口类 实现类 aop 拦截器 测试类 执行结论 多切面的情况 代理失效场景 总结 Spring 一开始最强大的就是 IOC / AOP 两大核心功能,我们今天一起来学习一下 Spring AOP 常见注解和执行顺序. Spring Aop 的常用注解 首先我们一起来回顾一下 Spring Aop 中常用的几个注解: @Before 前置通知:目标方法之前执行 @After 后置通知:目标方法之后执行(始终执行) @After

  • SpringBoot/Spring AOP默认动态代理方式实例详解

    目录 1. springboot 2.x 及以上版本 2. Springboot 1.x 3.SpringBoot 2.x 为何默认使用 Cglib 总结: Spring 5.x中AOP默认依旧使用JDK动态代理 SpringBoot 2.x开始,AOP为了解决使用JDK动态代理可能导致的类型转换异常,而使用CGLIB. 在SpringBoot 2.x中,AOP如果需要替换使用JDK动态代理可以通过配置项spring.aop.proxy-target-class=false来进行修改,proxy

  • Spring数据源及配置文件数据加密实现过程详解

    The following example shows the corresponding XML configuration: <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driverCl

  • Spring boot项目使用thymeleaf模板过程详解

    在spring boot 项目中使用thymeleaf模板,将后台数据传递给前台界面. 1.将后台数据传递给前台有很多种方式,可以将后台要传递的数据转换成json格式,去传递给前台,也可以通过model形式去传递出去,这篇博客主要是使用thymeleaf模板,将后台数据传递给前台. 2.首先要在spring boot 项目中添加如下依赖: <dependency> <groupId>org.springframework.boot</groupId> <artif

  • Spring Boot Async异步执行任务过程详解

    异步调用就是不用等待结果的返回就执行后面的逻辑,同步调用则需要等带结果再执行后面的逻辑. 通常我们使用异步操作都会去创建一个线程执行一段逻辑,然后把这个线程丢到线程池中去执行,代码如下: ExecutorService executorService = Executors.newFixedThreadPool(10); executorService.execute(() -> { try { // 业务逻辑 } catch (Exception e) { e.printStackTrace(

随机推荐