首页 > 技术文章 > AOP

qg000 2020-05-18 14:54 原文

python aop

参考文章:https://www.jianshu.com/p/4c588eec1be1

python的aop由@语法糖来实现,@语法糖就是个装饰器模式。能够这么实现是因为在python中函数就是对象。因此,对象:

  • 可以赋值给一个变量
  • 可以在其他函数中定义
  • 函数可以返回另一个函数
  • 函数作为参数传递

直接给个demo:

# 装饰器就是把其他函数作为参数的函数
def my_new_decorator(a_function_to_decorate):

    def the_wrapper_function():
      
        print "Before the function runs"

        a_function_to_decorate()

        print "After the function runs"

    return the_wrapper_function

def a_stand_alone_function():
    print "I am a stand alone function, don't you dare modify me"

a_stand_alone_function()
# 输出: I am a stand alone function, don't you dare modify me

# 相当于the_wrapper_function() & a_function_to_dacorate = a_stand_alone_function
a_function_decorated = my_new_decorator(a_stand_alone_function)
a_function_decorated()
# 输出:
# Before the function runs
# I am a stand alone function, don't you dare modify me
# After the function runs

所以上面的语法使用语法糖之后就是:

@my_new_decorator
def another_stand_alone_function():
    print "Leave me alone"

another_stand_alone_function()

像java一样一个注解就能解决的事情,那么java aop的时候函数是有参数的, python呢?

# 可以装饰带参数的函数
def a_decorator_passing_arguments(function_to_decorate):
    def a_wrapper_accepting_arguments(arg1, arg2):
        print "I got args! Look:", arg1, arg2
        function_to_decorate(arg1, arg2)
    return a_wrapper_accepting_arguments

@a_decorator_passing_arguments
def print_full_name(first_name, last_name):
    print "My name is", first_name, last_name

print_full_name("Peter", "Venkman")
# 输出:
#I got args! Look: Peter Venkman
#My name is Peter Venkman

好,但是java aop和参数是没有关系的,这里就是2个参数,怎么搞? kwargs?即使是kwargs对被装饰的函数也是有限定要求的。

go aop

修改函数

这里有个go版本的aop:https://github.com/gogap/aop

go的aop应该是很多人会单独去实现,但是官方并没有标准的aop实现。

像这个项目的readme之中的例子:

func (p *Auth) Login(userName string, password string) bool {
	p.Before(userName, password)
	defer p.After(userName, password)
	
	if userName == "zeal" && password == "gogap" {
		return true
	}
	return false
}

这个并不是aop只是修改了函数,不是python这种形式

reflect.MakeFunc

如果仿照python这么写的话:

func a_function_to_decorate() {
      fmt.Println("Hello world")
}

func my_new_decorator(a_function_to_decorate interface{}) {
      fmt.Println("before")
      // error: cannot call non-function a_function_to_decorate (type interface {})
      a_function_to_decorate() 
      fmt.Println("after")
}

func main() {
      my_new_decorator(a_function_to_decorate)
}

用interface传入一个函数,但是go是静态语言interface{}并不是function实现了空interface{},但是interface{}并不是function。

所以怎么办呢,必须确认传入的参数是function,之后才能使用某种方式来进行调用。那就要用到反射了。

func MakeTimedFunction(f interface{}) interface{} {
   rf := reflect.TypeOf(f)
   if rf.Kind() != reflect.Func {
      panic("非Reflect.Func")
   }
   vf := reflect.ValueOf(f)
   wrapperF := reflect.MakeFunc(rf, func(in []reflect.Value) []reflect.Value {
      start := time.Now()
      out := vf.Call(in)
      end := time.Now()
      fmt.Printf("calling %s took %v\n", runtime.FuncForPC(vf.Pointer()).Name(), end.Sub(start))
      return out
   })
   return wrapperF.Interface()
}

func time1() {
   fmt.Println("time1Func===starting")
   time.Sleep(1 * time.Second)
   fmt.Println("time1Func===ending")
}

func time2(a int) int {
   fmt.Println("time2Func===starting")
   time.Sleep(time.Duration(a) * time.Second)
   result := a * 2
   fmt.Println("time2Func===ending")
   return result
}

func main() {
   timed := MakeTimedFunction(time1).(func())
   timed()
   timedToo := MakeTimedFunction(time2).(func(int) int)
   time2Val := timedToo(5)
   fmt.Println(time2Val)
}

go版本monkey patch

参考:https://blog.csdn.net/sqxww123/article/details/101777075

go的monkeypatch先不研究了

java aop

待续

推荐阅读