通过闭包和模式匹配来实现Groovy的AOP?

时间:2015-09-17 18:19:40

标签: java regex groovy closures aop

我有一个抽象的基础POGO:

abstract class AuthorizingResource {
    void authorize(String credential) {
        if(!credentialIsValid(credential)) {
            throw new AuthorizationException(credential)
        }
    }

    boolean credentialIsValid(String credential) {
        // Do stuff to determine yea or nay
    }
}

许多具体的子类如下:

class FizzResource extends AuthorizingResource {
    List<Fizz> getAllFizzes(String credential) {
        authorize(credential)

        List<Fizz> fizzes

        // Do stuff

        fizzes
    }

    Fizz getFizzById(String credential, Long id) {
        authorize(credential)

        Fizz fizz

        // Do stuff

        fizz
    }

    void considerTheLillies(Buzz buzz) {
        // Do stuff
    }

    void upsertFizz(String credential, Fizz fizz) {
        authorize(credential)

        // Do stuff
    }
}

正如您所看到的,有几件事情正在发生:

  • 我想要经过身份验证/授权的任何FizzResource方法,我需要在方法顶部手动调用authorize(...)
  • 某些方法(considerTheLillies)不需要进行修改

我想知道我是否可以通过使用闭包调用authorize(...)来模仿AOP(所以我不必无意中添加它)可以使用某种模式来选择“换行”的方法封闭内部。在FizzResource的特定情况下,这将是包含“*Fizz*”的任何方法,但该模式应该(理想情况下)是任何有效的正则表达式。 无法改变的一件事是,任何接受credential arg的方法都无法修改其签名。

基本上,像Spring AOP或Google Guice的方法拦截器,但使用原生的Groovy闭包。

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

您可以将GroovyInterceptablefizz一起使用。请注意,名称中的任何abstract class AuthorizingResource implements GroovyInterceptable { def invoked = [] def validator = [credentialIsValid : { true }] void authorize(String credential) { if ( !validator.credentialIsValid(credential) ) { throw new RuntimeException(credential) } } def invokeMethod(String method, args) { if (method.toLowerCase().contains('fizz')) { metaClass.getMetaMethod('authorize', String).invoke(this, args[0]) invoked.add( 'authorized ' + method ) } return metaClass .getMetaMethod(method, args*.getClass() as Class[]) .invoke(this, args) } } class Fizz { String name } class FizzResource extends AuthorizingResource { List<Fizz> getAllFizzes(String credential) { ['all fizzes'] } Fizz getFizzById(String credential, Long id) { new Fizz(name: 'john doe') } def considerTheLillies() { 42 } } res = new FizzResource() assert res.getAllFizzes('cred') == ['all fizzes'] assert res.considerTheLillies() == 42 assert res.getFizzById('cred', 10l).name == 'john doe' assert res.invoked == ['authorized getAllFizzes', 'authorized getFizzById'] 都将匹配:

Option Private Module

答案 1 :(得分:0)

我无法停止考虑基于闭包的解决方案。我想出了一些Javascript样式代码,使用了闭包和贴图。它没有继承:

class AuthorizingResource {
    void authorize(String credential) {
        if(!credentialIsValid(credential)) {
            throw new RuntimeException(credential)
        }
    }
    boolean credentialIsValid(String credential) { true }
}

class Fizz {}

abstract class FizzResource {
    abstract List<Fizz> getAllFizzes(String credential)
    abstract int getFizzById(String credential, Long id)
    abstract void considerTheLillies(buzz)

    static createFizzResource(authorized) {
        def auth = new AuthorizingResource()
        def authorize = { auth.authorize it; authorized << it }

        return [ 
            getAllFizzes       : { String credential -> ['fizz list'] },
            getFizzById        : { String credential, Long id -> 42 },
            considerTheLillies : { buzz -> }
        ]
        .collectEntries { entry ->
            entry.key.toLowerCase().contains('fizz') ? 
                [(entry.key) : { Object[] args -> 
                    authorize(args[0]); entry.value(*args) 
                }] : 
                entry
        } as FizzResource

    }
}

测试:

def authorized = []

def fizz = FizzResource.createFizzResource(authorized)
assert authorized == []
assert fizz.getAllFizzes('getAllFizzes cred') == ['fizz list']

fizz.considerTheLillies null
assert authorized == ['getAllFizzes cred']

assert fizz.getFizzById('fizz by id cred', 90l) == 42
assert authorized == ['getAllFizzes cred', 'fizz by id cred']

请注意,authorized列表非常愚蠢,仅用于assert目的。