Github源码下载地址:https://github.com/chenxingxing6/sourcecode/tree/master/code-springaop


一、前言

AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方
式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。

Aop相关专业术语:

  1. Aspect(切面): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的Advice。
  2. Jointpoint(连接点):表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它joint point。
  3. Pointcut(切点):表示一组 joint point,这些 joint point或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。
  4. Advice(增强):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通before、after 和around 来区别是在每个 joint point 之前、之后还是代替执行的代码。 Target(目标对象):织入 Advice的目标对象.。
  5. Weaving(织入):将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程。

AOP底层使用动态代理实现。包括两种方式:

使用JDK动态代理实现。
使用cglib来实现

通知类型

前置通知:在方法之前执行
后置通知:在方法之后执行
异常通知:方法出现异常执行
最终通知:在后置之后执行
环绕通知:在方法之前和之后执行​​​​​​​


二、自己实现AOP代理(jdk代理)

2.1需求

1.前置通知,后置返回通知,环绕通知,后置通知,异常通知
2.自己实现一个简单版IOC容器
3.通过动态代理 + 通知注解类实现
4.定义切入点,正则表达式 @pointcut

2.2实现思路

服务启动时,将项目中的bean注入到容器里面,对应有切面进行代理的bean,重新生成代理对象,替换原理的对象。

①被代理类;
②被代理类要实现的接口;
③代理类;
④动态创建“代理类的对象”的类;
⑤注解类:
 a. 切面注解类,注解在类上:@Aspect
 b. 各种通知注解,注解在方法上:
   __@Before
   __@AfterReturning
   __@After
   __@AfterThrowing
   __@Around
⑥IOC容器:BeanFactory

2.3项目结构

2.4如何配置,测试项目

本项目配置切面,只支持@MyPointcut方式,支持正则表达式;然后将pointcut放到对应切面通知上。

1.编写Aspect切面
2.测试
只支持jdk动态代理

package com.demo1;import com.aop.annotation.*;
import com.aop.aspect.AbstractAspect;
import com.aop.aspect.JoinPoint;
import com.ioc.annotation.MyComponent;/*** @Author: cxx* @Date: 2019/10/3 11:25* 日志切面*/
@MyAspect
@MyComponent
public class LogAspect extends AbstractAspect{@MyPointcut("com.demo1.*")private void myPointcut(){}@MyAround(value = "myPointcut()")public Object around(JoinPoint joinPoint){Long start = System.currentTimeMillis();System.out.println("环绕通知start....");Object obj= joinPoint.proceed();System.out.println("环绕通知end....");Long end = System.currentTimeMillis();System.out.println("执行方法耗时:" + String.valueOf(end - start));return obj;}
}
2.5 核心代码AopBeanContext
package com.aop.core;import com.aop.aspect.AspectHandler;
import com.aop.aspect.CheckResult;
import com.aop.aspect.IAspectHandler;
import com.ioc.core.MyIoc;
import javafx.util.Pair;import java.util.HashMap;
import java.util.Map;/*** @Author: cxx* @Date: 2019/10/3 13:45*/
public class AopBeanContext {private static IAspectHandler aspectHandler = null;static {init();}public static Object getObject(Class clz){Object target = MyIoc.getObject(clz);if (target == null){throw new RuntimeException("容器中获取不到实例");}Pair<Object, CheckResult> aspectResult = aspectHandler.getAspectInstance(clz.getTypeName());// 没有切面if (aspectResult == null){return target;}// 创建代理类return ProxyBeanFactory.newProxyBean(target, aspectResult);}private static void init(){createProxyBeanContext(MyIoc.getBeanFactory());}// 根据切点,创建有代理类的bean容器public static void createProxyBeanContext(Map<String, Object> iocMap){aspectHandler = new AspectHandler(iocMap);}
}
2.6 核心代码BeanInvocationHandler
package com.aop.core;import com.aop.annotation.AdviceEnum;
import com.aop.aspect.AbstractAspect;
import com.aop.aspect.CheckResult;
import com.aop.aspect.JoinPoint;
import javafx.util.Pair;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;/*** @Author: cxx* @Date: 2019/10/3 15:35* @Desc: 环绕通知先不实现*/
public class BeanInvocationHandler implements InvocationHandler {// 目标类private Object target;// 切面相关信息private Pair<Object, CheckResult> acpectResult;public BeanInvocationHandler(Object target, Pair<Object, CheckResult> acpectResult) {this.target = target;this.acpectResult = acpectResult;}/*** 内部类实现环绕通知*/class MyJoinPoint implements JoinPoint{private Method method;private Object[] args;public MyJoinPoint(Method method, Object[] args) {this.method = method;this.args = args;}@Overridepublic Object proceed() {try {return method.invoke(target, args);} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}return null;}}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 切面类AbstractAspect aspcet = (AbstractAspect) acpectResult.getKey();// 通知方式CheckResult runType = acpectResult.getValue();boolean isAround = runType.isRunAround();JoinPoint joinPoint = null;if (isAround){joinPoint = new MyJoinPoint(method, args);}Object result = null;try {// 1.前置通知if (runType.isRunBefore()){runAspectInstance(AdviceEnum.BEFORE, aspcet, args);}// 2.环绕通知if (isAround){result = aspcet.around(joinPoint);}else {result = method.invoke(target, args);}// 3.返回通知if (runType.isRunAfterReturning()){runAspectInstance(AdviceEnum.AFTER_RETURNING, aspcet, args, result);}return result;}catch (Exception e){// 4.异常通知if (runType.isRunAfterThrowing()){runAspectInstance(AdviceEnum.AFTER_THROWING, aspcet, args, e);}}finally {// 5.后置通知if (runType.isRunAfter()){runAspectInstance(AdviceEnum.AFTER, aspcet, args);}}return result;}private void runAspectInstance(AdviceEnum adviceEnum, AbstractAspect aspect, Object[] args){this.runAspectInstance(adviceEnum, aspect, args, null, null);}private void runAspectInstance(AdviceEnum adviceEnum, AbstractAspect aspect, Object[] args, Object result){this.runAspectInstance(adviceEnum, aspect, args, null, result);}private void runAspectInstance(AdviceEnum adviceEnum, AbstractAspect aspect, Object[] args, Throwable e){this.runAspectInstance(adviceEnum, aspect, args, e, null);}/*** 执行切面实例* @param adviceEnum* @param aspect* @param args*/private void runAspectInstance(AdviceEnum adviceEnum, AbstractAspect aspect, Object[] args, Throwable e, Object result){try {switch (adviceEnum){case BEFORE:{aspect.before();break;}case AFTER_RETURNING:{aspect.afterReturning(result);break;}case AFTER_THROWING:{aspect.afterThrowable(e);break;}case AFTER:{aspect.after();break;}default:{break;}}}catch (Exception ee){ee.printStackTrace();}}
}

三、测试结果

package com.aop;import com.aop.core.AopBeanContext;
import com.demo1.ILogService;
import com.demo1.LogService;/*** @Author: cxx* @Date: 2019/10/3 11:34*/
public class MainTest {public static void main(String[] args) {//  01.测试 修改ioc.properties scan.package=com.demo//IUserService userService = (IUserService) AopBeanContext.getObject(UserService.class);//userService.delete("100");// 02.环绕通知测试 修改ioc.properties scan.package=com.demo1ILogService logService = (ILogService) AopBeanContext.getObject(LogService.class);logService.printLog("test....");}
}


第七篇 - 手写Aop(面向切面编程)相关推荐

  1. AOP面向切面编程之全局日志打印/统计接口耗时

    目录 一.什么是AOP 二.AOP使用场景 三.使用AOP的好处 四.先举个例子理解AOP面向切面编程 五.Spring5.X的AOP切入点表达式有这些种写法 六.实战基于Spring的AOP快速实现 ...

  2. 大数据WEB阶段Spring框架 AOP面向切面编程(二)

    Spring AOP面向切面编程(二) 一.切入点的execution表达式 execution的表达形式: execution(修饰符? 返回值类型 所在包类? 方法名(参数列表) 异常?) ?表示 ...

  3. AOP(面向切面编程)大概了解一下

    前言 上一篇在聊MemoryCache的时候,用到了Autofac提供的拦截器进行面向切面编程,很明显能体会到其优势,既然涉及到了,那就趁热打铁,一起来探探面向切面编程. 正文 1. 概述 在软件业, ...

  4. AOP—面向切面编程

    前言 上一篇在聊MemoryCache的时候,用到了Autofac提供的拦截器进行面向切面编程,很明显能体会到其优势,既然涉及到了,那就趁热打铁,一起来探探面向切面编程. 正文 概述 在软件业,AOP ...

  5. java aop面向切面编程

    最近一直在学java的spring boot,一直没有弄明白aop面向切面编程是什么意思.看到一篇文章写得很清楚,终于弄明白了,原来跟python的装饰器一样的效果.http://www.cnblog ...

  6. 切面是异步还是同步操作‘_Autofac的AOP面向切面编程研究

    什么是AOP: 我的理解是 把系统性的编程工作封装起来 =>我给这个取个名字叫 "Aspect",然后通过AOP技术把它切进我们的业务逻辑代码 => "业务& ...

  7. Javascript aop(面向切面编程)之around(环绕)

    Aop又叫面向切面编程,其中"通知"是切面的具体实现,分为before(前置通知).after(后置通知).around(环绕通知),用过spring的同学肯定对它非常熟悉,而在j ...

  8. Autofac的AOP面向切面编程研究

    我的理解是 把系统性的编程工作封装起来 =>我给这个取个名字叫 "Aspect",然后通过AOP技术把它切进我们的业务逻辑代码 => "业务" 这样 ...

  9. python aop编程_学习笔记: AOP面向切面编程和C#多种实现

    AOP:面向切面编程   编程思想 OOP:一切皆对象,对象交互组成功能,功能叠加组成模块,模块叠加组成系统 类--砖头     系统--房子 类--细胞     系统--人 面向对象是非常适合做大型 ...

最新文章

  1. SVN中update to revision与revert to revision的区别
  2. 字符串函数实现(strlen,strcpy,strcmp,strcat,strrev)
  3. 智能手机系统对进程生命周期的管理
  4. java学习笔记2022.1.17
  5. 基于Java的Selenium学习笔记——Assert
  6. 一篇文章普及各种ios基本知识(防止奸商忽悠、鉴别假冒翻新机、知识入门必备)
  7. 数据结构与算法--数组中出一次的数字
  8. java 设计模式原则_Java设计模式的七大原则
  9. 《深入理解 Spring Cloud 与微服务构建》第四章 Dubbo
  10. 在python语言中用=判断两个数值是否相等_在Python语言中,要判断两个值是否不等,应使用下列哪个运算符?...
  11. js中比較好的继承方式
  12. 浅谈ACM算法学习与有效训练
  13. Java太阳系行星运动模型
  14. 动态爬虫之手机版QQ空间登录
  15. AWS abbreviation
  16. 2016苹果开发者账号注册申请流程链接
  17. 如何使用QQ群日历和群活动进行会议室安排
  18. css文字一半居左一半居右
  19. 四旋翼无人机——导航、制导与控制的概念
  20. http、https 等 常用默认端口号

热门文章

  1. Nexus SSR激活
  2. 逻辑回归模型预测股票涨跌
  3. 复试这样做真的会被刷!避雷指南请收好!
  4. PHP电子合同对接流程,在线电子合同的签订流程
  5. EMQ的安装以及MQTT的简单使用
  6. 我所理解的iOS开发高手
  7. 程序员 IT 行业职业生涯探讨
  8. java面试100题。
  9. Pr和AE之间的区别是什么?
  10. win10局域网无法访问