Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
/aopPublic

Aspect Oriented Programming For Golang

License

NotificationsYou must be signed in to change notification settings

gogap/aop

Repository files navigation

Aspect Oriented Programming For Golang

current version is in alpha, welcome to submit your ideas (api is not stable current version)

Basic Usage

define struct

typeAuthstruct {}func (p*Auth)Login(userName,passwordstring)bool {ifuserName=="zeal"&&password=="gogap" {returntrue}returnfalse}// use join point to get Args from real methodfunc (p*Auth)Before(jp aop.JoinPointer) {username:=""jp.Args().MapTo(func(u,pstring) {username=u})fmt.Printf("Before Login: %s\n",username)}// the args is same as Loginfunc (p*Auth)After(username,passwordstring) {fmt.Printf("After Login: %s %s\n",username,password)}// use join point to around the real func of loginfunc (p*Auth)Around(pjp aop.ProceedingJoinPointer) {fmt.Println("@Begin Around")ret:=pjp.Proceed("fakeName","fakePassword")ret.MapTo(func(loginResultbool) {fmt.Println("@Proceed Result is",loginResult)})fmt.Println("@End Around")}

In this case, we want callBefore() func beforeLogin(), andAfter() func afterLogin()

In general, we will do it like as following

func (p*Auth)Login(userNamestring,passwordstring)bool {p.Before(userName,password)deferp.After(userName,password)ifuserName=="zeal"&&password=="gogap" {returntrue}returnfalse}

So, if we have more funcs to call before and after, it will pollution the real logic funcLogin(), we want a proxy help us to invokeBefore() andAfter() automatic.

That was what AOP does.

Step 1: Define Beans factory

beanFactory:=aop.NewClassicBeanFactory()beanFactory.RegisterBean("auth",new(Auth))

Step 2: Define Aspect

aspect:=aop.NewAspect("aspect_1","auth")aspect.SetBeanFactory(beanFactory)

Step 3: Define Pointcut

pointcut:=aop.NewPointcut("pointcut_1").Execution(`Login()`)aspect.AddPointcut(pointcut)

Step 4: Add Advice

aspect.AddAdvice(&aop.Advice{Ordering:aop.Before,Method:"Before",PointcutRefID:"pointcut_1"})aspect.AddAdvice(&aop.Advice{Ordering:aop.After,Method:"After",PointcutRefID:"pointcut_1"})aspect.AddAdvice(&aop.Advice{Ordering:aop.Around,Method:"Around",PointcutRefID:"pointcut_1"})

Step 5: Create AOP

gogapAop:=aop.NewAOP()gogapAop.SetBeanFactory(beanFactory)gogapAop.AddAspect(aspect)

Setp 6: Get Proxy

proxy,err:=gogapAop.GetProxy("auth")

Last Step: Enjoy

login:=proxy.Method(new(Auth).Login).(func(string,string)bool)("zeal","gogap")fmt.Println("login result:",login)

output

$> go run main.goBefore Login: zealAfter Login: zeal gogapLogin result:true

Advance

Pointcut expression

every condition expression is regex expression

pointcut:=aop.NewPointcut("pointcut_1")// will trigger the advice while call loginpointcut.Execution(`Login()`)// will trigger the advice will call any funcpointcut.Execution(`.*?`)// will not trigger the advice will call any funcpointcut.NotExecution(`Login()`)
other conditions:
  • WithIn
  • NotWithIn
  • Bean
  • NotBean
// will trigger the advie while we call Login// and in bean named authpointcut.Execution(`Login()`).Bean(`auth`)// will trigger the advie while we call Login// and in bean named auth and sysAuthpointcut.Execution(`Login()`).Bean(`auth`).Bean(`sysAuth`)// will trigger the advie while we call Login// and in bean named auth not sysAuthpointcut.Execution(`Login()`).Bean(`auth`).NotBean(`sysAuth`)// will trigger the advie while we call Login// and the call stacktrace should contain example/aop/mainpointcut.Execution(`Login()`).WithIn(`example/aop/main`)

Do not want to assertion func type

proxy.Invoke(new(Auth).Login,"zeal","errorpassword").End(func(resultbool) {login=result})

Weaving other beans into aspect

define a bean
typeFoostruct {}// @AfterReturning, the method could have args of aop.Result,// it will get the result from real func return valuesfunc (p*Foo)Bar(result aop.Result) {result.MapTo(func(vbool) {fmt.Println("Bar Bar Bar .... Result is:",v)})}
register bean
beanFactory.RegisterBean("foo",new(Foo))
create aspect
aspectFoo:=aop.NewAspect("aspect_2","foo")aspectFoo.SetBeanFactory(beanFactory)
add advice
aspectFoo.AddAdvice(&aop.Advice{Ordering:aop.AfterReturning,Method:"Bar",PointcutRefID:"pointcut_1"})
add aspect into aop
gogapAop.AddAspect(aspectFoo)

result

Before Login: zealBar Bar Bar .... Result is:trueAfter Login: zeal gogapLogin result:true

Turn on trace for debug

err:=aop.StartTrace()....// use proxy to call your funcst,err:=aop.StopTrace()for_,item:=ranget.Items() {fmt.Println(item.ID,item.InvokeID,item.BeanRefID,item.Pointcut,item.Method)}
$> go run main.gogo run main.go==========Func Type Assertion==========Before Login: zeal@Begin Around@Login fakeName fakePassword@Proceed Result isfalse@End AroundAfter Login: zeal gogapLogin result:false================Invoke=================Before Login: zeal@Begin Around@Login fakeName fakePassword@Proceed Result isfalse@End AroundAfter Login: zeal errorpasswordLogin result:false1 aqpk3jjhssa5ul6pt0h0 auth main.(Auth).Login Before2 aqpk3jjhssa5ul6pt0h0 auth main.(Auth).Login Around3 aqpk3jjhssa5ul6pt0h0 auth main.(Auth).Login*Login4 aqpk3jjhssa5ul6pt0h0 foo main.(Auth).Login Bar5 aqpk3jjhssa5ul6pt0h0 auth main.(Auth).Login After6 aqpk3jjhssa5ul6pt0hg auth main.(Auth).Login Before7 aqpk3jjhssa5ul6pt0hg auth main.(Auth).Login Around8 aqpk3jjhssa5ul6pt0hg auth main.(Auth).Login*Login9 aqpk3jjhssa5ul6pt0hg foo main.(Auth).Login Bar10 aqpk3jjhssa5ul6pt0hg auth main.(Auth).Login After

the* means the real func in this call

About

Aspect Oriented Programming For Golang

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages


[8]ページ先頭

©2009-2025 Movatter.jp