【问题标题】:AOP for Groovy via closures and pattern matching?通过闭包和模式匹配实现 Groovy 的 AOP?
【发布时间】:2015-09-17 18:19:39
【问题描述】:

我有一个抽象基础 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 闭包。

有什么想法吗?

【问题讨论】:

标签: java regex groovy closures aop


【解决方案1】:

您可以将invokeMethodGroovyInterceptable 一起使用。请注意,名称中的任何fizz 都会匹配:

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']

【讨论】:

    【解决方案2】:

    我一直在思考基于闭包的解决方案。我想出了一些 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 目的。

    【讨论】:

      猜你喜欢
      • 2016-05-12
      • 2015-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-31
      • 1970-01-01
      相关资源
      最近更新 更多