Spring 实现Aop的原理

Spring Aop

AOP(Aspect Oriented Programming),意思为:面向切面编程,是一种通过预编译方式和运行期间动态代理实现程序功能的统一维护的技术。SpringAOP不是一种新的AOP实现,其底层采用的是JDK/CGLIB动态代理。Spring Aop,依托Spring的IOC容器,能够为容器中管理的对象生成动态代理对象,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

Spring 实现Aop的原理

上一篇简单介绍了动态代理的原理区别和简单使用,现在我们来简单回顾一下:

1.动态代理(其局限性,被代理对象必须要实现接口,才能产生代理对象,如果没有接口将不能使用动态代理技术)
Proxy.newProxyInstance(classLoader.Interface[] arr,InvocationMandeler handler)

2.cglib代理(其优点,作为第三方代理技术,cglib可以对任何类生成代理,代理的原理是对目标对象进行继承代理。但如果目标是被final修饰符修饰,那么该类无法被cglib代理)

总结,有接口存在时,优先使用动态动态,无接口时用cglib代理。spring aop封装了动态代理代码,我们就不需要手写动态代理代码,还封装了cglib代理,可以对任何类实现代理增强。

Spring Aop中的名词解释

  1. 连接点( Joinpoint): 所谓连接点是指那些被拦截到的点,在spring中,这些点指的是方法,因为spring只支持方法类型的连接点

  2. Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义

  3. Advice(通知/增强):所谓通知是指拦截到Joinpoint之后要做的事情就是通知,通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)

    • 前置通知(Before Advice):在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。
      例如,TestAspect 中的 doBefore 方法。

    • 后置通知(After Advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
      例如,ServiceAspect 中的 returnAfter 方法,所以 Teser 中调用 UserService.delete 抛出异常时,returnAfter 方法仍然执行。

    • 返回后通知(After Return Advice):在某连接点正常完成后执行的通知,不包括抛出异常的情况。

    • 环绕通知(Around Advice):包围一个连接点的通知,类似 Web 中 Servlet 规范中的 Filter 的 doFilter 方法。可以在方法的调用前后完成自定义的行为, 也可以选择不执行。
      例如,ServiceAspect 中的 around 方法。

    • 异常通知(After Throwing Advice):在方法抛出异常退出时执行的通知 。

  4. Introduction(引介):引介是一种特殊的通知在不修改代码的前提下,Introduction可以以运行期为类,动态地添加一些方法或Field

  5. Target(目标对象):代理的目标对象

  6. Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程,spring采用动态代理来织入,而AspectJ采用编译期织入和类装载期织入

  7. Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类Aspect(切面),是切入点和通知(引介)的结合。

应用示例

  1. 对所有进行登录操作的用户进行拦截,打印登录日志存入数据库
    对所需要拦截的方法添加注解:@LogAnnotation
    /*** 用户登录** @param zh      帐号* @param mm      密码* @throws Exception* 添加注解 @LogAnnotation,进行拦截*/@PostMapping("login")@LogAnnotation(value = "登陆",remark = "登陆",operation = "登陆操作")public ResponseVo login(String zh, String mm) throws Exception {//TODO 登录逻辑}
  1. 实现注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAnnotation {String value() default "";String remark() default "";String operation() default "";int type() default 0;
}
  1. 在每次请求上述注解的方法之前都先被拦截进入下述操作中

@Aspect
@Component
public class LogAspect extends BaseController {@Autowiredprivate LogService logService;private Logger logger = LoggerFactory.getLogger(LogAspect.class);public LogAspect() {}@Around("within(com.*..*.controller.*)")public Object aroundd(ProceedingJoinPoint point) throws Throwable {LogPo logPo = null;Object obj = null;try {MethodSignature methodSignature = (MethodSignature)point.getSignature();LogAnnotation logAnnotation = (LogAnnotation)methodSignature.getMethod().getAnnotation(LogAnnotation.class);if (logAnnotation == null) {obj = point.proceed();} else {logPo = this.before(logAnnotation, methodSignature);obj = point.proceed();this.after(logPo, obj);}} catch (Throwable var10) {if (logPo != null) {logPo.setResult(1);logPo.setErrMsg(var10.getMessage());logPo.setEndTime(new Date());} else if (obj == null) {obj = new ResponseVo("服务运行异常!", var10.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value());}this.logger.error("[ERROR]服务运行异常!", var10);throw var10;} finally {if (logPo != null) {this.logService.addLog(logPo);}return obj;}}private void after(LogPo logPo, Object obj) {HttpServletRequest req = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();this.logger.debug("[调用后]响应数据:{}", obj);logPo.setEndTime(new Date());String trackId = req.getParameter("trackId");trackId = StringUtils.isBlank(trackId) ? req.getParameter("token") : trackId;if (StringUtils.isNotBlank(trackId)) {trackId = this.redisUtil.getString(BaseController.LOG_LOGIN_NAME_REDIS_KEY + trackId);}logPo.setLoginName(StringUtils.isBlank(trackId) ? "is null" : trackId);if (obj != null && obj instanceof ResponseVo) {ResponseVo res = (ResponseVo)obj;logPo.setResult(res.getResult());logPo.setErrMsg(StringUtils.isNotBlank(res.getErrMsg()) ? res.getErrMsg() : res.getMsg());if ("login".equals(logPo.getMethod()) && "is null".equals(logPo.getLoginName())) {String s = req.getParameter("zh");if (StringUtils.isNotBlank(s)) {logPo.setLoginName(s);}}} else {logPo.setResult(0);}}private LogPo before(LogAnnotation logAnnotation, MethodSignature methodSignature) {LogPo logPo = new LogPo(logAnnotation.type(), logAnnotation.value(), logAnnotation.operation(), logAnnotation.remark());HttpServletRequest req = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();String host = req.getLocalAddr() + ":" + req.getLocalPort();logPo.setUserIp(this.getIp(req));logPo.setClassName(methodSignature.getDeclaringTypeName());logPo.setMethod(methodSignature.getName());logPo.setServerIp(host);return logPo;}
}

按照三个步骤操作之后,只需要定义添加一个注解即可,无需在每个方法中再写打印日志操作,减少了代码量,对项目开发提供了极大地便利。

Spring 实现Aop的原理与示例相关推荐

  1. Spring 之AOP技术原理剖析

    2019独角兽企业重金招聘Python工程师标准>>> 转载自:http://greenyouyou.blog.163.com/blog/static/138388147201181 ...

  2. 框架源码专题:Spring的Aop实现原理,Spring AOP 与 AspectJ 的关系

    文章目录 1. Spring AOP 与 AspectJ 的关系 2. JDK和Cglib动态代理的区别 3. Spring AOP应用案例 4. Spring AOP有几种配置方式? 5. Spri ...

  3. aop实现原理-动态代理CGLib代理

    那接下来的话,那咱们Spring当中,这个AOP,咱们先说概念,咱们先不写具体代码,咱们就是聊,聊Spring的AOP,Spring能帮我们干啥呢,我告诉你,Spring他作为对象的容器,Spring ...

  4. Spring AOP 实现原理与 CGLIB 应用--转

    AOP(Aspect Orient Programming),作为面向对象编程的一种补充,广泛应用于处理一些具有横切性质的系统级服务,如事务管理.安全检查.缓存.对象池管理等.AOP 实现的关键就在于 ...

  5. Spring AOP 实现原理与 CGLIB 应用

    WeiboGoogle+用电子邮件发送本页面 10 AOP(Aspect Orient Programming),作为面向对象编程的一种补充,广泛应用于处理一些具有横切性质的系统级服务,如事务管理.安 ...

  6. Spring AOP实现原理,从代理说起

    前言 为了理解Spring AOP,我们先来了解一下Java的代理模式 什么是代理? 举个例子来说明代理的作用: 假设我们想邀请一位明星,那么并不是直接联系明星,而是联系明星的经纪人,来达到同样的目的 ...

  7. 深入解析Spring架构与设计原理-AOP

    2019独角兽企业重金招聘Python工程师标准>>> 关于AOP的个人理解 AOP联盟定义的AOP体系结构把与AOP相关的概念大致分为了由高到低.从使用到实现的三个层次.关于这个体 ...

  8. 【Spring源码】Spring中的AOP底层原理分析

    AOP中的几个概念 Advisor 和 Advice Advice,我们通常都会把他翻译为通知,其实很不好理解,其实他还有另外一个意思,就是"建议",我觉得把Advice理解为&q ...

  9. Spring 容器AOP的实现原理——动态代理

    本文来自极客学院 Spring 容器AOP的实现原理--动态代理 之前写了一篇关于IOC的博客--<Spring容器IOC解析及简单实现>,今天再来聊聊AOP.大家都知道Spring的两大 ...

最新文章

  1. R假设检验之莫德中位数检验(Mood‘s Median Test)
  2. 机智云5.0推出IoT套件GoKit4.0 可实现物联网应用协同开发
  3. c语言太极图编程语言,利用C语言的Cairo图形库绘制太极图实例教程.pdf
  4. .net core 微服务下的手工签名实现,以及消除中文乱码
  5. 幕乔美化版音乐网站源码
  6. ansible常用基础命令整合
  7. memcached的缺点
  8. linux中断机制--理解中断上半部/下半部、软中断、tasklet、工作队列(可调度、可睡眠)
  9. 03-06 APP-UI自动化测试-等待方式
  10. Unable to compile class for JSP异常
  11. 热力图怎么做_LncRNA这么热,5分左右的LncRNA研究文章应该怎么做
  12. Data Member的布局
  13. 【Python】:修改图片后缀
  14. python列表的负数索引
  15. python3刷火车票_Python3实现抢火车票功能(上)
  16. 表征学习 Representation Learning(特征学习、表示学习)是什么?
  17. 骑士cms任意代码执行
  18. windows ios良心软件推荐
  19. 软考初级信息处理技术员基础知识考点(建议收藏)
  20. 三国杀 中的概率计算 几何分布的期望和方差分析

热门文章

  1. vue 实现简易卡包效果
  2. linux dig dns,dig 与 DNS解析
  3. 真遺憾,你來的不是地方
  4. Creator双指缩放和拖动无黑边
  5. 安卓11状态栏图标不显示问题调查
  6. UGO模型 ACL特殊权限
  7. Flutte-- 国际化l10n笔记
  8. JAVA中File类的getPath()、getAbsolutePath()、getCanonical()
  9. 文本特征提取_02:Word2Vec词嵌入矩阵
  10. 忍者必须死3 通关 服务器维护,《忍者必须死3》11月5日停服维护公告