【AOP】Spring AOP基础 + 实践 完整记录
Spring AOP的基础概念
=============================================================
AOP(Aspect-Oriented Programming), 即 面向切面编程, 它与 OOP( Object-Oriented Programming, 面向对象编程) 相辅相成, 提供了与 OOP 不同的抽象软件结构的视角.
在 OOP 中, 我们以类(class)作为我们的基本单元, 而 AOP 中的基本单元是 Aspect(切面)。
==============================================================
基础概念图:
有了上面这张原理图,那么关于AOP面向切面编程的核心几个概念,就可以顺利铺开了:
1》join point【连接点】
在spring aop中,认为原有代码中所有的方法都是join point。
2》point cut【切点】
在不改变原有代码的情况下,想多干点事情,那就需要定义point cut,切点。切点的任务是通过一组表达式来匹配要在哪个join point切入,并且匹配要在这个join point的什么位置切入。
3》advice【增强逻辑】
根据1,2切入了原有代码后,要做些什么事情?这多做的事情就是advice,也就是多处理的一些逻辑。比如,你的原有方法是对数据的保存方法,项目交付后,新需求是需要将这些保存操作在日志中记录下来,并且不能更改原有代码,这就是增强逻辑。
advice增强逻辑你是准备放在原有代码之前还是之后,有以下几种:
before advice, 在 join point 前被执行的 advice. 虽然 before advice 是在 join point 前被执行, 但是它并不能够阻止 join point 的执行, 除非发生了异常(即我们在 before advice 代码中, 不能人为地决定是否继续执行 join point 中的代码)
after return advice, 在一个 join point 正常返回后执行的 advice
after throwing advice, 当一个 join point 抛出异常后执行的 advice
after(final) advice, 无论一个 join point 是正常退出还是发生了异常, 都会被执行的 advice.
around advice, 在 join point 前和 joint point 退出后都执行的 advice. 这个是最常用的 advice.
4》weaving【织入】
现在有了原有代码,有了新的增强逻辑。将这两部分代码连接在一起的过程,就是织入weaving。
根据不同的实现技术, AOP织入有三种方式:
编译器织入, 这要求有特殊的Java编译器.
类装载期织入, 这需要有特殊的类装载器.
动态代理织入, 在运行期为目标类添加增强(Advice)生成子类的方式.
Spring 采用动态代理织入, 而AspectJ采用编译器织入和类装载期织入.
5》Target【目标对象】
原有代码和增强逻辑织入在一起,重新生成的就是目标对象Target,也叫adviced object.
Spring Aop使用运行时代理的方式实现Aspect,因此adviced object是一个代理对象。
【在 Spring AOP 中, 一个 AOP 代理是一个 JDK 动态代理对象或 CGLIB 代理对象。】
注意, adviced object 指的不是原来的类, 而是织入 advice 后所产生的代理类.
【关于java中代理的概念,类型,区别和理解:
https://www.cnblogs.com/hongcong/p/5806024.html
https://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html
可以去看上面两篇文章,我自己还没有心思去研究。
但我记住了一句话:CGLIB方式不能代理final类。也就是说Spring AOP的切口不能切在final类上了。
】
6》aspect【切面】
aspect切面,是由point cut和advice组合而成的。既包含了连接点也就是切点的定义,也有增强逻辑的具体实现。
===========================================
到这里,一个概念就顺利的出来了:Spring AOP就是负责实施切面的框架, 它将切面所定义的横切逻辑织入到切面所指定的连接点中.
===========================================
Spring Aop的实现和使用的各种情况
=======================================================
要在Spring中通过注解方式使用AOP,需要下面两步:
1》在配置文件中配置
<!-- 自动扫描注解 -->
<context:component-scan base-package="com.sxd" />
<!--Spring aop 使用注解的方式-->
<aop:aspectj-autoproxy />
2》定义切面【aspect】
切面包括 切点【point cut】 和 增强逻辑【advice】
【下面aspect中已经显示了point cut的各种定义表达式 和 各种类的advice】
【具体使用,应该按照实际使用逻辑选择性使用即可!!!】
package com.sxd.aop; import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component; import java.util.Objects; /**
* 切面定义
* ①在类上定义@Aspect和@Component
* ②@Pointcut()定义切点
* ③adive方法上,声明在哪一个切点上切入 加入增强逻辑
*/
@Aspect
@Component
public class Aspects { /**
* execution() 表达式:用来匹配执行方法的连接点
* 【..(两个点)代表零个或多个】
* 【本例子中 第一个*代表方法的返回值类型可以为任何类型 如果本方法为void,也符合切入条件】
* 【本例子中 第一个..代表controller包以及子包下】
* 【本例子中 第二个*代表这个包下的任意类】
* 【本例子中 第三个*代表这个包下的任意类中的任意方法】
* 【本例子中 第二个..代表有无参数都可以被切入】
*
* args 如果想要切入的方法的参数要符合什么类型的话
* 【本例子代表入参中,第一个参数类型需要为String类型的才会被切入,之后有零个入参或多个入参】
*
*/
@Pointcut(value = "execution(* com.sxd.controller..*.*(..)) && args(String,..)")
public void pointCut1(){} /**
* within() 表达式用于匹配这个包下的任意类
*/
@Pointcut(value = "within(com.sxd.controller.*)")
public void pointCut2(){} /**
* this() 表达式限定了匹配这个类的实例下的方法
*/
@Pointcut(value = "this(com.sxd.controller.MainController)")
public void pointCut3(){} /**
* bean() 匹配IOC容器中的bean的名称
*/
@Pointcut(value = "bean(memberService)")
public void pointCut4(){} /**
* 下面是各种advice的展示
*
* 1》advice的执行优先级: around方法执行前》before》【方法自己】》around方法执行后》after》afterReturning
* 2》若有异常
* advice的执行优先级:around方法执行前》before》【方法自己】》around方法执行后》after》afterReturning
* 很奇怪为什么两次都是一样的执行优先级,为什么没有进afterThrowing().因为使用了around。
* 3》注意:Spring AOP的环绕通知会影响到AfterThrowing通知的运行,不要同时使用!
*
* 4》注意:在切面的advice里面,一定不要让异常抛出去,影响原方法的执行和返回。
* 5》JoinPoint 即原方法的入参
* 6》returning即原方法的返回值
* 7》如果原方法没有返回值,而这里的advice定义了returning,即使pointCut可以匹配上切点,也不会切入原方法
*/ @Before("pointCut1()")
public void justBefore(JoinPoint joinPoint){
System.out.println("切入方法前");
} @After("pointCut1()")
public void justAfter(JoinPoint joinPoint){
Object[] arr = joinPoint.getArgs();
if(Objects.nonNull(arr) && arr.length >0){
System.out.println((String)arr[0]);
System.out.println((Integer)arr[1]);
}
System.out.println("切入方法后");
} @AfterReturning(pointcut = "pointCut1()",returning = "returnVal")
public void justAfterReturn(JoinPoint joinPoint,Object returnVal){
System.out.println(returnVal.toString());
System.out.println("在方法执行完,并未抛异常,能正确返回值的情况下,在返回值之前切入");
} @AfterThrowing(pointcut = "pointCut1()",throwing = "err")
public void justAfterThrow(JoinPoint joinPoint,Throwable err){
System.out.println("在方法执行,抛异常的情况下,切入");
} @Around("pointCut1()")
public Object justAround(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("环绕型切入,方法执行前");
Object a = null;
try {
a = proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("环绕型切入,方法执行后");
return a;
} }
3》上面两步 就把aop写完了 ,最后要测试一下各种情况
package com.sxd.controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody; @Controller
public class MainController { @ResponseBody
@RequestMapping("do")
public String doSomething(){
return "无参";
} @ResponseBody
@RequestMapping("do2")
public String doSomething2(String a){
return "有参"+a;
} @ResponseBody
@RequestMapping("do3")
public String doSomething3(Integer a,String b){ return "整数"+a+"---字符串"+b; } @ResponseBody
@RequestMapping("do4")
public String doSomething4(String a,Integer b){
return "字符串"+a+"---整数"+b;
} @ResponseBody
@RequestMapping("do5")
public String doSomething5(String a,Integer b) throws Throwable{
return "字符串转成数字"+Integer.parseInt(a)+"---整数"+b;
} @ResponseBody
@RequestMapping("do6")
public void doSomething6(){
System.out.println("无返回值的");
}
}
发请求 测试即可。
======================================================================
补充:
1》两个或多个位置定义切点
方法1:
@Pointcut(value = "(execution(* net.shopxx.xgn.controller.MemberCybController.cjtg(..))) or (execution(* net.shopxx.hunan.MemberCybController.cjtg(..)))")
public void endbgDeal() {
}
方法2:
@Pointcut(value = "execution(* net.shopxx.xgn.controller.MemberCybController.cjtg(..))")
public void endbgDeal1(){ }
@Pointcut(value = "execution(* net.shopxx.hunan.MemberCybController.cjtg(..))")
public void endbgDeal2(){ } @Pointcut(value = "endbgDeal1() || endbgDeal2()")
public void endbgDeal() {
}
【AOP】Spring AOP基础 + 实践 完整记录的更多相关文章
- Spring 学习——Spring AOP——AOP概念篇
AOP AOP的定义:AOP,Aspect Oriented Programming的缩写,意为面向切面编程,是通过预编译或运行期动态代理实现程序功能处理的统一维护的一种技术 实现方式 预编译 Asp ...
- spring aop与aspectj
AOP:面向切面编程 简介 AOP解决的问题:将核心业务代码与外围业务(日志记录.权限校验.异常处理.事务控制)代码分离出来,提高模块化,降低代码耦合度,使职责更单一. AOP应用场景: 日志记录.权 ...
- spring aop介绍和示例
参考:<Spring in Action> 一.AOP介绍 AOP是Aspect Oriented Programming的缩写,意思是面向切面编程. 应用中有一些功能使用非常普遍,比如事 ...
- Spring5.0源码学习系列之Spring AOP简述
前言介绍 附录:Spring源码学习专栏 在前面章节的学习中,我们对Spring框架的IOC实现源码有了一定的了解,接着本文继续学习Springframework一个核心的技术点AOP技术. 在学习S ...
- Spring Aop技术原理分析
本篇文章从Aop xml元素的解析开始,分析了Aop在Spring中所使用到的技术.包括Aop各元素在容器中的表示方式.Aop自动代理的技术.代理对象的生成及Aop拦截链的调用等等.将这些技术串联起来 ...
- Spring Aop、拦截器、过滤器的区别
Filter过滤器:拦截web访问url地址.Interceptor拦截器:拦截以 .action结尾的url,拦截Action的访问.Spring AOP拦截器:只能拦截Spring管理Bean的访 ...
- Spring AOP统一异常处理
1.添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...
- spring-第十六篇之AOP面向切面编程之Spring AOP
1.上一篇介绍了AspectJ在AOP的简单应用,让我们了解到它的作用就是:开发者无需修改源代码,但又可以为这些组件的方法添加新的功能. AOP的实现可分为两类(根据AOP修改源码的时机划分): 1& ...
- spring boot基础学习教程
Spring boot 标签(空格分隔): springboot HelloWorld 什么是spring boot Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新 ...
随机推荐
- leetcode 【 Rotate Image 】python 实现
题目: You are given an n x n 2D matrix representing an image. Rotate the image by 90 degrees (clockwis ...
- ios开发学习笔记001-C语言基础知识
先来学习一下C语言基础知识,总结如下: 在xcode下编写代码. 1.编写代码 2.编译:cc –c 文件名.c 编译成功会生成一个 .o的目标文件 3.链接:把目标文件.o和系统自带的库合并在一起, ...
- uncompyle2反编译python的.py文件
前几天学用github,一不小心把a.py文件给删除了,由于1天没有提交,也无法找回.突然发现同a.py文件生成的编译文件a.pyc还在,逐去搜索一番反编译的方法. 查询得知python比较好的工具u ...
- 什么是事务?MySQL如何支持事务?
什么是事务? 事务是由一步或几步数据库操作序列组成逻辑执行单元,这系列操作要么全部执行,要么全部放弃执行.程序和事务是两个不同的概念.一般而言:一段程序中可能包含多个事务.(说白了就是几步的数据库操作 ...
- Android view相关与自定义View
一.关于view的机制的问答 1.gesturedetector和ontouchevent的区别 gesturedetector指的是手势检测器,根据动态手势的运动特性,提出了速率边沿检测算法来分割手 ...
- SpringCloud Eureka参数配置项详解
SpringCloud Eureka参数配置项详解(转) Eureka涉及到的参数配置项数量众多,它的很多功能都是通过参数配置来实现的,了解这些参数的含义有助于我们更好的应用Eureka的各种功能,下 ...
- [NOI2003][bzoj1507] 文本编辑器 editor [splay]
其实看明白了就是一道水题 毕竟模板 splay敲一发,插入一个串的时候先把它构建成一棵平衡树,再挂到原来的splay上面去即可 没别的了,上代码 #include<iostream> #i ...
- pdf生成
要用本文的方法生成PDF文件,需要两个控件:itextsharp.dll和ICSharpCode.SharpZipLib.dll,由于示例代码实在太多,我将代码全部整理出来,放在另外一个文件“示例代码 ...
- bzoj 4131: 并行博弈 (parallel)
bzoj 4131: 并行博弈 (parallel) Description lyp和ld在一个n*m的棋盘上玩翻转棋,游戏棋盘坐标假设为(x, y),1 ≤ x ≤ n,1 ≤ y ≤ m,这个游戏 ...
- 【转】手摸手,带你用vue撸后台 系列三(实战篇)
前言 在前面两篇文章中已经把基础工作环境构建完成,也已经把后台核心的登录和权限完成了,现在手摸手,一起进入实操. Element 去年十月份开始用vue做管理后台的时候毫不犹豫的就选择了Elemen, ...