一、AOP概念以及什么时候会用到
- AOP就是java中常常说的切面编程,是一种思维或者说程序设计。
- AOP:Aspect-Oriented Programming
- AOP是spring或者springboot框架中特有的一种编程思维,有时候咱们业务中会有一些开始前的校验或者完结后的其余发送告诉记录日志等这样的需要,尽管在本人自身的业务中也能够写,然而,比拟啰嗦以及代码芜杂,因为它不是咱们的次要业务逻辑。这个时候,就能够用AOP思维来将这些校验或者记录日志等这样的非次要逻辑做成一个切面,哪里想用就间接用这个切面就OK。
- 某种程度上,我认为,切面就像一个函数一样,函数是形象出一段逻辑,而切面其实也是形象了一段逻辑,然而它比函数从我的项目整体架构来讲,更加的解耦。
二、AOP在spring/springboot框架中处于的位置
- spring或者springboot框架中,最外围的思维有两个,一个是IOC管制反转,一个就是咱们AOP切面编程。
- IOC:我的项目中,咱们常常是多个对象合作配合实现咱们的逻辑,IOC思维是将对象的创立、治理、销毁等交给spring容器来操作,而不是对象本人外部去创立或者治理这些对象,相当于找了一个中介或者代理来治理对象。-----字面意思就是将对象管制治理的责任反转给spring容器或者代理了。【对象解耦】
- AOP:将非次要非功能性的代码形象成一个切面,从架构上进行代码解耦、复用。【代码解耦】
- 开发中,咱们次要创立和操作的是不同的对象,对象多了就尝试将对象解耦,IOC派上用场,接着,咱们在具体的书写业务逻辑的时候,非功能性或者非次要逻辑越来越多的时候,尝试将这块代码形象,能够形象成函数或者aop切面,依据咱们本人的业务进行思考,避免次要业务逻辑中太多if else判断。
三、AOP外围知识点
备注:思考实现一个切面都须要哪些步骤?(1)必定须要写具体的切面业务逻辑(对应aspect)(2)那写好逻辑后什么时候执行?是次要逻辑前还是次要逻辑后?(对应advice,执行机会)(3)须要定义一个在哪里应用切面,比方某个insert办法要应用切面,校验insert之前的一些null或者空字符串(对应join point)(4)不是所有办法都用到这个切面,怎么管制?(通过point cut来管制和匹配)
连接点
join point,程序的一个执行点,相似类的一个办法,办法里边一个代码块
切入点
Point cut,捕捉连接点的代码构造,定一个代码逻辑用来捕捉某个连接点的实现逻辑
切面
aspect,具体被执行的代码逻辑,就是咱们想要的那些校验、记录日志、发送短信告诉等这些逻辑实现代码
告诉
advice,定义在连接点什么机会来执行aspect,蕴含before(次要逻辑之前执行)、after(次要逻辑之后执行)、around(前、后都执行)
四、简略实现一个AOP(据说有四种常见的实现形式,这里只看springboot注解形式)
如果想要提交一个销假申请,在申请单有性别、销假工夫等,创立申请单之前校验提交的参数(sex、startDate、endDate)不能为空,将这个校验逻辑应用切面来实现。
自定义一个注解ApplyAnnotation
import java.lang.annotation.*;@Target({ ElementType.METHOD, ElementType.TYPE })@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface ApplyAnnotation {}
创立aspect类
package portal.aop;import com.alibaba.fastjson.JSONObject;import com.fasterxml.jackson.databind.ObjectMapper;import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang.StringUtils;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.util.Objects;/** * 申请单插入前校验的切面 * */@Slf4j@Aspect@Componentpublic class ApplyAspect { /** * 校验:对sex、startDate、endEnd参数进行校验 * @param joinPoint * @throws RRException */ @Before("@annotation(ApplyAnnotation)") public void before(JoinPoint joinPoint) throws RRException { if(joinPoint.getArgs()!=null && joinPoint.getArgs().length>0) { //获取参数应用joinPoint.getArgs String json = JSONObject.toJSONString(joinPoint.getArgs()[0]); // 将参数转换成一个entity对象 UpdateApplyForm form = objectMapper.convertValue(joinPoint.getArgs()[0], UpdateApplyForm.class); if (Objects.isNull(form.getSex())) { throw new Exception("参数谬误,请查看参数sex是否传递"); } if (Objects.isNull(form.getStartDate())) { throw new Exception("参数谬误,请查看参数startDate是否传递"); } if (Objects.isNull(form.getEndDate())) { throw new Exception("参数谬误,请查看参数endDate是否传递"); } } } @After("@annotation(ApplyViewAnnotation)") public void after(JoinPoint joinPoint) { // 能够在次要逻辑之后执行一些 记录日志或者发送短信告诉等逻辑 } }
在想要应用的中央增加注解
/** * 在controller的createApply办法应用注解 * 创立一条销假申请,加上ApplyAnnotation注解后,会在执行createApply办法之前去调用切面的before办法进行校验 * @param form * @return * @throws Exception */ @PostMapping("/create-apply") @ApplyAnnotation public R createApply(@RequestBody UpdateApplyForm form) throws Exception { // 次要业务逻辑 portalLogic.createApply(form); return R.ok(); }
体验完上述的实例之后,会发现,咱们的次要逻辑portalLogic.createApply(form)没有混入一些奇奇怪怪的if else进行校验,而是间接用一个注解就将这些校验逻辑实现了,从代码档次看,让代码更加的简洁,从架构上看,将校验逻辑和次要逻辑进行解耦。
五、AOP的实现原理
- 咱们的AOP到底是怎么实现的?怎么让咱们的次要逻辑代码执行前或者后 去执行了切面逻辑呢?
- 实际上AOP充分利用了代理来将切面的逻辑 “织入” 了咱们本人的次要业务代码中,外表看不到,是springboot框架通过代理来实现的。(实际上代理分为动态代理和动静代理)
- 代理,我了解的就是一个中介,将想要做的事件交给一个中介/代理来干,所有的操作都让这个中介干和实现。
- AOP实现用到的代理有两种形式,jdk动静代理和cglib代理,须要提前了解这两种代理模式和异同点。
- 具体的能够查看:aop外围源码原理详解