面向切面编程AOP——加锁、cache、logging、trace、同步等这些较通用的操作,如果都写一个类,则每个用到这些功能的类使用多继承非常难看,AOP就是解决这个问题的,python AOP就是装饰器
面向切面编程(AOP)是一种编程思想,与OOP并不矛盾,只是它们的关注点相同。面向对象的目的在于抽象和管理,而面向切面的目的在于解耦和复用。
举两个大家都接触过的AOP的例子:
1)java中mybatis的@Transactional注解,大家知道被这个注解注释的函数立即就能获得DB的事务能力。
2)python中的with threading.Lock(),大家知道,被这个with代码块包裹的部分立即获得同步的锁机制。
这样我们把事务和加锁这两种与业务无关的逻辑抽象出来,在逻辑上解耦,并且可以轻松的做到代码复用。
二、上下文管理器contextlib
当然你可以使用with上下文管理器实现一些AOP的思想,这里有个模块叫contextlib可以帮助你简易的实现上下文管理器。
上下文管理最常见的例子是with open('file') as fh,回收打开句柄的例子。
这种方式还是比较麻烦的,下面我们看一下python中的装饰器怎么样实现AOP编程。
三、装饰器:AOP的语法糖
python中的装饰器就是设计来实现切面注入功能的。下面给出几个例子,这几个例子都是在生产环境验证过的。
其中的任务管理机是伪代码,需要自己实现写数据库的逻辑。
1、重试逻辑
只要do函数被@retry_exp装饰,便可以获得指数退避的重试能力。
- @retry_exp(max_retries=10)
- def do():
- # do whatever
- pass
那retry_exp是如何实现的呢?
- def retry_exp(max_retries=3, max_wait_interval=10, period=1, rand=False):
- def _retry(func):
- def __retry(*args, **kwargs):
- MAX_RETRIES = max_retries
- MAX_WAIT_INTERVAL = max_wait_interval
- PERIOD = period
- RAND = rand
- retries = 0
- error = None
- ok = False
- while retries < MAX_RETRIES:
- try:
- ret = func(*args, **kwargs)
- ok = True
- return ret
- except Exception, ex:
- error = ex
- finally:
- if not ok:
- sleep_time = min(2 ** retries * PERIOD if not RAND else randint(0, 2 ** retries) * PERIOD, MAX_WAIT_INTERVAL)
- time.sleep(sleep_time)
- retries += 1
- if retries == MAX_RETRIES:
- if error:
- raise error
- else:
- raise Exception("unknown")
- return __retry
- return _retry
2、降级开关
只要do函数被@degrade装饰,就会安装app名称校验redis里的开关,一旦发现开关关闭,则do函数不被执行,也就是降级。
- @degrade
- def do(app):
- # do whatever
- pass
那么degrade是怎样实现的呢?
- def degrade(app):
- def _wrapper(function):
- def __wrapper(*args, **kwargs):
- value = None
- try:
- redis = codis_pool.get_connection()
- value = redis.get("dmonitor:degrade:%s" % app)
- except Exception, _:
- logger.info(traceback.format_exc())
- if not value or int(value) != 1:
- function()
- logger.info("[degrade] is_on: %s" % app)
- else:
- logger.info("[degrade] is_off: %s" % app)
- return __wrapper
- return _wrapper
3、任务状态机
这个是最常用的,我们需要跟踪落盘DB一个任务的执行状态(等待调度,执行中,执行成功,执行失败)
一旦do方法被@tasks_decorator装饰,就获得了这样的能力。对item_param(是个json)中task_id指明的任务进行状态管理。
- @tasks_decorator
- def do(item_param):
- # do whatever
- pass
tasks_decorator是怎样实现的呢?
- def tasks_decorator(function):
- def _wrap(*args, **kwargs):
- param_dict = kwargs.get('item_param')
- task_id = param_dict.get('task_id')
- try:
- param_dict.update({'status': TaskStatus.Waiting, 'start_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')})
- try:
- manager_dao.save_task(param_dict)
- except Exception, ex:
- pass
- _update_task_status(task_id, TaskStatus.Doing)
- function(*args, **kwargs)
- _update_task_status(task_id, TaskStatus.Done)
- except Exception as e:
- time.sleep(0.5)
- _update_task_status(task_id, TaskStatus.Fail, unicode(e.message))
- raise
- return _wrap
4、全局唯一性
在分布式+异步环境中,如果想保证exactly once是需要额外的逻辑的,其实主要是实现唯一键,一旦唯一键实现了,就可以使用公共缓存redis进行唯一键判定了。
do函数被unique装饰,那么对于task_id对应的任务,全局只会执行一次。
- @unique
- def do(task_id):
- # do whatever
- pass
unique是怎样实现的呢?
- def unique(function):
- def _wrap(*args, **kwargs):
- task_id = kwargs.get('task_id')
- try:
- redis = codis_pool.get_connection()
- key = "unique:%s" % task_id
- if not redis.setnx(key):
- redis.expire(key, 24*60*60)
- function(*args, **kwargs)
- except Exception as e:
- logger.error(traceback.format_exc())
- raise
- return _wrap
四、总结
AOP在少量增加代码复杂度的前提下,显著的获得以下优点:
1、使得功能逻辑和业务逻辑解耦,功能和业务的修改完全独立,代码结构清晰,开发方便
2、一键注入,代码复用程度高,扩展方便
应用举例
1
2
3
4
5
|
abstract class Worker { abstract void locked(); abstract void accessDataObject(); abstract void unlocked(); } |

应用范围
实现项目
作用
面向切面编程AOP——加锁、cache、logging、trace、同步等这些较通用的操作,如果都写一个类,则每个用到这些功能的类使用多继承非常难看,AOP就是解决这个问题的,python AOP就是装饰器的更多相关文章
- Method Swizzling和AOP(面向切面编程)实践
Method Swizzling和AOP(面向切面编程)实践 参考: http://www.cocoachina.com/ios/20150120/10959.html 上一篇介绍了 Objectiv ...
- 依赖注入(DI)有助于应用对象之间的解耦,而面向切面编程(AOP)有助于横切关注点与所影响的对象之间的解耦(转good)
依赖注入(DI)有助于应用对象之间的解耦,而面向切面编程(AOP)有助于横切关注点与所影响的对象之间的解耦.所谓横切关注点,即影响应用多处的功能,这些功能各个应用模块都需要,但又不是其主要关注点,常见 ...
- 杂项-编程:AOP(面向切面编程)
ylbtech-杂项-编程:AOP(面向切面编程) 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一 ...
- 面向切面编程AOP
本文的主要内容(AOP): 1.AOP面向切面编程的相关概念(思想.原理.相关术语) 2.AOP编程底层实现机制(动态代理机制:JDK代理.Cglib代理) 3.Spring的传统AOP编程的案例(计 ...
- Python装饰器与面向切面编程
今天来讨论一下装饰器.装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数 ...
- 【转】Python装饰器与面向切面编程
原文请参考: http://www.cnblogs.com/huxi/archive/2011/03/01/1967600.html 今天来讨论一下装饰器.装饰器是一个很著名的设计模式,经常被用于有切 ...
- 从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之十 || AOP面向切面编程浅解析:简单日志记录 + 服务切面缓存
代码已上传Github+Gitee,文末有地址 上回<从壹开始前后端分离[ .NET Core2.0 Api + Vue 2.0 + AOP + 分布式]框架之九 || 依赖注入IoC学习 + ...
- 面向切面编程--AOP(转)
add by zhj:面向切面编程就是在不修改函数A的前提下,在函数A前后插入业务逻辑B, C, D...这其实算是功能分解,将大模块S=A+B+C+D+……分解为独立的小功能A,B,C,D……,模块 ...
- Python装饰器与面向切面编程(转)
add by zhj: 装饰器的作用是将代码中可以独立的功能独立出来,实现代码复用,下面那个用于统计函数运行时间的装饰器就是很好的例子,我们不用修改原有的函数和调用原有函数的地方,这遵循了开闭原则.装 ...
随机推荐
- Centos7中rc.local设置springboot项目开机自启动
在Centos7下,rc.local文件,开机默认是不执行的 1.进入rc.local中 路径如下图
- DRF概述
目录 一. REST 1. 什么是编程? 2. 什么是REST? 二. 知识准备 1. CBV(class based view) 2. 类方法 classmethod和classonlymethod ...
- CentOS升级kernel
CentOS升级kernel 升级命令: yum update kernel yum update kernel-devel yum update kernel-firmware yum update ...
- 【ztree】隐藏显示节点
//显示隐藏的节点 var nodes = zTreeObj.getNodesByParam("isHidden", true); zTreeObj.showNodes(nodes ...
- PHP设计模式 - 中介者模式
中介者模式用于开发一个对象,这个对象能够在类似对象相互之间不直接相互的情况下传送或者调解对这些对象的集合的修改. 一般处理具有类似属性,需要保持同步的非耦合对象时,最佳的做法就是中介者模式.PHP中不 ...
- [转帖]Flink(一)Flink的入门简介
Flink(一)Flink的入门简介 https://www.cnblogs.com/frankdeng/p/9400622.html 一. Flink的引入 这几年大数据的飞速发展,出现了很多热门的 ...
- Android调试桥 adb安装详解
Android调试桥(adb) 一.简介 Android 调试桥 (adb) 是一种功能多样的命令行工具,可让您与设备进行通信.adb 命令便于执行各种设备操作(例如安装和调试应用),并提供对 Uni ...
- STM32学习笔记 —— 1.1 什么是寄存器(概念分析)
问题引入: 用一句话回答以下问题: 什么是寄存器? 什么是寄存器映射? 什么是存储器映射? (本章重点在 1.1.3 和 1.1.4) 1.1 STM32芯片实物图 (图) 学会看丝印图 芯片型号.内 ...
- C# vb .net图像合成-合成文字
在.net中,如何简单快捷地实现图像合成呢,比如合成文字,合成艺术字,多张图片叠加合成等等?答案是调用SharpImage!专业图像特效滤镜和合成类库.下面开始演示关键代码,您也可以在文末下载全部源码 ...
- sqlserver 2005 数据库的差异备份与还原
找到一个可靠的步骤,点开链接:http://blog.csdn.net/kevindr/article/details/22154323