【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团队提供的全新框架,其设计目的是用来简化新 ...
随机推荐
- CSS中behavior属性语法简介
本文和大家重点讨论一下CSS中behavior属性语法的使用,在进行CSS网页布局的时候,我们经遇到刷新要保留表单里内容的时候,习惯的做法使用cookie,但是那样做实在是很麻烦,CSS中的behav ...
- @SpringBootApplication的扫描范围
在公共类自定义一个全局异常类,实现全局捕获异常,在另一个服务中调用的时候,发现没有生效 因此我添加了一个@ComponentScan("com.wuhen.jwt.common") ...
- Python 连接数据库失败
什么是 PyMySQL? PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库,Python2中则使用mysqldb. PyMySQL 遵循 Python 数据库 AP ...
- MapReduce 使用案例
MapReduce 使用案例 MapReduce在面试过程中出现的频率还是挺高的,尤其是数据挖掘等岗位.通常面试官会出一个大数据题目,需要被试者根据题目设计基于MapReduce的算法来解答.我在一个 ...
- manjaro安装anaconda出错
出错信息: ==> Creating package "anaconda"... -> Generating .PKGINFO file... -> Gene ...
- 学习成绩>=90分的同学用A表示,60-89分之间的用B表示,60分以下的用利用条件运算符的嵌套来完成此题:C表示。
# -*- coding: utf8 -*- # Author:wxq #python 2.7 #题目:学习成绩>=90分的同学用A表示,60-89分之间的用B表示,60分以下的用利用条件运算符 ...
- 【homework week5】初步了解敏捷开发——自由与约束的哲学统一
“自由与束缚的哲学统一”或许不该放到标题上去,毕竟它只是我灵光一闪的感悟.但这个spark让我感到高中到大学的哲学应该也没有白学,这是让人非常兴奋的一件事. 所以我还是把它放到了标题上. 来谈敏捷软件 ...
- 【转】tomcat与apache,tomcat与servlet的区别
tomcat与apache的区别:(转自:http://blog.csdn.net/longzs/article/details/10959945) 1.apache支持静态页,tomcat支持动态的 ...
- 设计模式(一)单例模式:2-懒汉模式(Lazy)
思想: 相比于饿汉模式,懒汉模式实际中的应用更多,因为在系统中,“被用到时再初始化”是更佳的解决方案. 设计思想与饿汉模式类似,同样是持有一个自身的引用,只是将 new 的动作延迟到 getinsta ...
- mvcs项目搭建
项目结构 下载链接:http://pan.baidu.com/s/1hsGtShA