AOP简介

利用面向对象的方法可以很好的组织代码,也可以继承的方式实现代码重用。但是项目中总是会出现一些重复的代码,并且不太方便使用继承的方式把他们重用管理起来,比如说通用日志打印,事务处理和安全检查等。我们可以将这些代码封装起来,做成通用模块,但是还是需要在代码中每处需要的地方进行显示调用,使用起来不方便。这是时候就是利用AOP的时候。

AOP是一种编程范式,用来解决特定的问题,不能解决所有问题,可以看做是OOP的补充,常见的编程范式还有:

  • 面向过程编程;
  • 面向对象编程;
  • 面向函数编程(函数式编程);
  • 事件驱动编程(GUI开发中比较常见);
  • 面向切面编程

AOP的常见使用场景

  • 性能监控,在方法调用前后记录调用时间,方法执行太长或超时报警;
  • 缓存代理,缓存某方法的返回值,下次执行该方法时,直接从缓存里获取;
  • 软件破解,使用AOP修改软件的验证类的判断逻辑;
  • 记录日志,在方法执行前后记录系统日志;
  • 工作流系统,工作流系统需要将业务代码和流程引擎代码混合在一起执行,那么我们可以使用AOP将其分离,并动态挂接业务;
  • 权限验证,方法执行前验证是否有权限执行当前方法,没有则抛出没有权限执行异常,由业务代码捕捉;
  • 事务处理 。

Spring AOP相关概念

  • AOP:这种在运行时(或者编译时或者加载时),动态地将某些公共代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程;
  • 切面(Aspect):A modularization of a concern that cuts across multiple classes。在Spring中切面就是一个标注@AspectJ的类,不要想得太复杂;
  • 连接点(Joinpoint):方法执行过程中的某个点,是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时、抛出异常时、甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为;
  • 通知(advice):描述切面要完成什么工作,以及在什么时间点进行工作;
  • Pointcut:用来匹配一组连接点,并且pointcut会关联advice,在pointcut匹配的连接点执行的时候,advice代码会被执行;
  • Introduction
  • Target object:被织入切面的对象;
  • AOP proxy : 包装了切面代码和target代码的对象,Spring中支持JDK动态代理和

    CGLIB,默认使用JDK动态代理,但是如果被代理的类没有实现接口,或者用户强制使用CGLIB,那么Spring会使用CGLIB代理;
  • Weaving:将切面代码添加到目标代码的过程,织入的类型有编译时织入,加载时织入和运行时织入(Spring是运行时织入)

SpringAOP可以应用5种类型的通知:

  • 前置通知(Before):在目标方法被调用之前调用通知功能。
  • 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么。(不管执行是否成功都执行都执行)
  • 返回通知(After-returning):在目标方法成功执行之后调用通知。
  • 异常通知(After-throwing):在目标方法抛出异常后调用通知。
  • 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。

Spring AOP相关

开启Aop

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AopConfig {
}

如果使用传统的配置方式的话,可按如下配置开启AOP功能。

<aop:aspectj-autoproxy/>

定义一个Aspect

Aspects (classes annotated with @Aspect) can have methods and fields, the same as any other class. They can also contain pointcut, advice, and introduction (inter-type) declarations.

可以使用普通Bean的定义方式,或者加@Aspect注解的方式定义。一旦一个类被标注成切面类,它就不会成为其他切面的代理对象。

定义一个PointCut

切面表达式可以由指示器,通配符和运算符组成。

  1. 指示器(Designators)
  • 匹配方法 execution() (重点掌握...)
  • 匹配注解 @target() @args() @within() @annotation()
  • 匹配包/类型 within()
  • 匹配对象 this() bean() target()
  • 匹配参数 args()
  1. Wildcards(通配符)
  • *匹配任意数量的字符
  • +匹配指定类及其子类
  • .. 一般用于匹配任意参数的子包或参数
  1. Operators(运算符)
  • && 与操作符
  • || 或操作符
  • ! 非操作符

下面给出一个定义PointCut的例子

package com.csx.demo.spring.boot.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component; @Component
@Aspect
public class MyAspect { //PointCut匹配的方法必须是Spring中bean的方法
//Pointcut可以有下列方式来定义或者通过&& || 和!的方式进行组合.
//下面定义的这些切入点就可以通过&& ||组合 private static Logger logger = LoggerFactory.getLogger(MyAspect.class); //*:代表方法的返回值可以是任何类型
//整个表达式匹配controller包下面任何的的echo方法,方法入参乐意是任意
@Pointcut("execution(* com.csx.demo.spring.boot.controller.*.echo(..))")
public void pointCut1(){} //代表echo方法必须有一个参数 参数的类型可以是任意类型
@Pointcut("execution(* com.csx.demo.spring.boot.controller.*.echo(*))")
public void pointCut2(){} //代表echo方法必须有两个参数,第一个类型任意,第二个类型必须是String
@Pointcut("execution(* com.csx.demo.spring.boot.controller.*.echo(*,String))")
public void pointCut3(){} //contrller包及其子包下面的任意类的任意方法
//需要注意的是with和@with都是正对包级别的
@Pointcut("within(com.csx.demo.spring.boot.controller..*)")
public void pointCut4(){} //使用RestController这个注解标注任意类的任意方法
@Pointcut("@within(org.springframework.web.bind.annotation.RestController)")
public void pointCut5(){} //用法和@Within类似
@Pointcut("@target(org.springframework.web.bind.annotation.RestController)")
public void pointCut10(){} //MyService这个接口实现类的任何方法
//如果MyService是一个类的话,那匹配这个类内部的所有方法
@Pointcut("this(com.csx.demo.spring.boot.service.MyService)")
public void pointCut6(){} @Pointcut("this(com.csx.demo.spring.boot.service.MyServiceImpl)")
public void pointCut7(){} //某个bean内部的所有方法
@Pointcut("bean(myServiceImpl)")
public void pointCut8(){} //@within和@target针对类的注解,@annotation是针对方法的注解
//匹配任何标注GetMaping注解的方法
@Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")
public void pointCut9(){} //匹配只有一个参数,参数类型是String的方法
@Pointcut("args(String)")
public void pointCut11(){} @Before("pointCut1()")
public void befor(){
logger.info("前置通知vvvv...");
logger.info("我要做些事情...");
} @After("pointCut1()")
public void after(){
logger.info("后置通知");
} @AfterReturning("pointCut1()")
public void afterReturn(){
logger.info("后置返回");
} @Around("pointCut1()")
public void around(ProceedingJoinPoint point) throws Throwable {
logger.info("环绕通知...");
logger.info("我要做些事情...");
point.proceed();
logger.info("结束环绕通知");
} }

Spring系列.AOP使用的更多相关文章

  1. Spring系列.AOP原理简析

    Spring AOP使用简介 Spring的两大核心功能是IOC和AOP.当我们使用Spring的AOP功能时是很方便的.只需要进行下面的配置即可. @Component @Aspect public ...

  2. Spring基础系列--AOP织入逻辑跟踪

    原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9619910.html 其实在之前的源码解读里面,关于织入的部分并没有说清楚,那些前置.后 ...

  3. Spring系列之AOP的原理及手动实现

    目录 Spring系列之IOC的原理及手动实现 Spring系列之DI的原理及手动实现 引入 到目前为止,我们已经完成了简易的IOC和DI的功能,虽然相比如Spring来说肯定是非常简陋的,但是毕竟我 ...

  4. Spring基础系列-AOP源码分析

    原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9560803.html 一.概述 Spring的两大特性:IOC和AOP. AOP是面向切 ...

  5. Spring系列(四):Spring AOP详解

    一.AOP是什么 AOP(面向切面编程),可以说是一种编程思想,其中的Spring AOP和AspectJ都是现实了这种编程思想.相对OOP(面向过程编程)来说,提供了另外一种编程方式,对于OOP过程 ...

  6. Spring系列(五):Spring AOP源码解析

    一.@EnableAspectJAutoProxy注解 在主配置类中添加@EnableAspectJAutoProxy注解,开启aop支持,那么@EnableAspectJAutoProxy到底做了什 ...

  7. Spring系列之aAOP AOP是什么?+xml方式实现aop+注解方式实现aop

    Spring系列之aop aop是什么?+xml方式实现aop+注解方式实现aop 什么是AOP? AOP为Aspect Oriented Programming 的缩写,意识为面向切面的编程,是通过 ...

  8. Spring系列26:Spring AOP 通知与顺序详解

    本文内容 如何声明通知 如何传递参数到通知方法中 多种通知多个切面的通知顺序 多个切面通知的顺序源码分析与图解 声明通知 Spring中有5种通知,通过对应的注解来声明: @BeforeBefore ...

  9. Spring系列之AOP实现的两种方式

    AOP常用的实现方式有两种,一种是采用声明的方式来实现(基于XML),一种是采用注解的方式来实现(基于AspectJ). 首先复习下AOP中一些比较重要的概念: Joinpoint(连接点):程序执行 ...

随机推荐

  1. 深入理解Java虚拟机(1)

        对于Java程序员,在虚拟机自动内存管理机制的帮助下,不需要再为每一个操作写配对的释放资源操作,不容易出现内存泄露和内存溢出问题.加深对Java虚拟机的理解,有助于在发现问题时精准定位问题,排 ...

  2. Istio-架构

    读书笔记整理 工作机制:分为控制面和数据面 控制面:Pilot, Mixer(接收来自Envoy上报的数据), Citadel(证书和密钥管理) 数据面:Envoy 工作流程: 自动注入 应用程序启动 ...

  3. 远程快速安装mysql

    远程服务器安装mysql数据库 https://www.cnblogs.com/renjidong/p/7047396.html 1.新开的云服务器,需要检测系统是否自带安装mysql # yum l ...

  4. vue中使用jsx

    vue中使用jsx 为什么需要使用jsx呢?这个需要搞清楚 其实vue官方也说了,对于那些非常多v-if v-else的情况,就可以尝试使用render函数或者jsx,不过render函数写简单的结构 ...

  5. MVC案例之通过配置切换底层存储源(面向接口)

    1.深入理解面向接口编程: 在类中调用接口的方法,而不必关心具体的实现.这将有利于代码的解耦.使程序有更好的可移植性 和可扩展性 动态修改 Customer 的存储方式:通过修改类路径下的 switc ...

  6. sku算法详解及Demo~接上篇

    前言 做过电商项目前端售卖的应该都遇见过不同规格产品库存的计算问题,业界名词叫做sku(stock Keeping Unit),库存量单元对应我们售卖的具体规格,比如一部手机具体型号规格,其中ipho ...

  7. conda虚拟环境安装

    一.背景 需要学习mxnet,建一个conda虚拟软件环境. 二.步骤 1.下载anaconda安装文件:https://mirrors.tuna.tsinghua.edu.cn/anaconda/m ...

  8. Rocket - tilelink - BusWrapper

    https://mp.weixin.qq.com/s/03BvgTNQtD75Guco6gUGQg   简单介绍BusWrapper的实现.   1. HasTLBusParams   定义SoC的挂 ...

  9. 【Storm】核心组件nimbus、supervisor、worker、executor、task

    nimbus 是整个集群的控管核心,负责topology的提交.运行状态监控.任务重新分配等工作. zk就是一个管理者,监控者. 总体描述:nimbus下命令(分配任务),zk监督执行(心跳监控wor ...

  10. Java实现 LeetCode 140 单词拆分 II(二)

    140. 单词拆分 II 给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,在字符串中增加空格来构建一个句子,使得句子中所有的单词都在词典中.返回所有这些可能的句子. 说明: 分 ...