面向切面编程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: 装饰器的作用是将代码中可以独立的功能独立出来,实现代码复用,下面那个用于统计函数运行时间的装饰器就是很好的例子,我们不用修改原有的函数和调用原有函数的地方,这遵循了开闭原则.装 ...
随机推荐
- 简单工厂(三)——JDK源码中的简单工厂
private static Calendar createCalendar(TimeZone zone,Locale aLocale) { CalendarProvider provider = L ...
- Javascript判斷function是否定義
jQuery可以用 isFunction() 來進行判斷 如果僅使用Javascript可以使用以下的方法 function isFunction(fn){ return typeof fn === ...
- RabbitMQ使用及与spring boot整合
1.MQ 消息队列(Message Queue,简称MQ)——应用程序和应用程序之间的通信方法 应用:不同进程Process/线程Thread之间通信 比较流行的中间件: ActiveMQ Rabbi ...
- ES6常用的新特性
1.Let&const <!DOCTYPE html> <html lang="en"> <head> <meta charset ...
- AVR单片机教程——旋转编码器
好久没写这个系列了.今天讲讲旋转编码器. 旋转编码器好像不是单片机玩家很常用的器件,但是我们的开发板上有,原因如下: 旋转编码器挺好用的.电位器能旋转的角度有限,旋转编码器可以无限圈旋转:旋转时不连续 ...
- 在Go中简单实现HTTP服务中间件
通常一个简单http服务框架,就是注册一堆路由,然后根据路由调用不同的逻辑去处理. 但实际上可能有一些统一的处理对几乎所有的路由都涉及到,比如日志,比如权限等等. 那么这个时候搞一个中间做预处理,是一 ...
- arm-linux-系列工具,ld,ar,as,objcopy
ref :http://www.360doc.com/content/14/0509/09/17268421_376009916.shtml 一.编译器相关知识学习 GNU GCC简介: GNU GC ...
- 华为云·寻找黑马程序员#【代码重构之路】如何“消除”if/else【华为云技术分享】
1. 背景 if/else是高级编程语言中最基础的功能,虽然 if/else 是必须的,但滥用 if/else,特别是各种大量的if/else嵌套,会对代码的可读性.可维护性造成很大伤害,对于阅读代码 ...
- Python 基础-import 与 from...import....
简单说说python import与from-import- 在python用import或者from-import来导入相应的模块.模块其实就一些函数和类的集合文件,它能实现一些相应的功能,当我们需 ...
- Kafka理解
1. 引言 最近使用Kafka做消息队列时,完成了基本的消息发送与接收,已上线运行.一方面防止出现Bug时自己不能及时定位问题,一方面网上的配置可能还可以更加优化,决定去了解下Kafka. 2. 配置 ...