1

Grails 2.4.x はこちら。

によって生成されたすべての Grails サービスのすべてのメソッドをgrails create-service <xyz>、次のロジックで「ラップ」/インターセプトする必要があります。

try {
    executeTheMethod()
} catch(MyAppException maExc) {
    log.error(ExceptionUtils.getStackTrace(maExc))
    myAppExceptionHandler.handleOrRethrow(maExc)
}

どこ:

  • log.error(...)クラスに注釈を付けるときに取得する SLF4J 提供のロガーです@Slf4j。と
  • ExceptionUtilsからのものorg.apache.commons:commons-lang3:3.4です。と
  • myAppExceptionHandlerタイプcom.example.myapp.MyAppExceptionHandlerです。と
  • この動作は、Grails サービスで定義された各メソッドに存在します (または、何らかの形で明示的に呼び出す必要がある場合に存在するオプションがあります)。

したがって、明らかにこのラッパー コードにはimport、これらのクラスのステートメントも含める必要があります。

たとえば、WidgetService次のようながあるとします。

class WidgetService {
    WidgetDataService widgetDataService = new WidgetDataService()

    Widget getWidgetById(Long widgetId) {
        List<Widget> widgets = widgetDataService.getAllWidgets()
        widgets.each {
            if(it.id.equals(widgetId)) {
                return it
            }
        }

        return null
    }
}

次に、この Groovy/Grails/クロージャ マジックが発生した後、次のように記述したかのようにコードを動作させる必要があります。

import groovy.util.logging.Slf4j
import org.apache.commons.lang3.exception.ExceptionUtils
import com.example.myapp.MyAppExceptionHandler

@Slf4j
class WidgetService {
    WidgetDataService widgetDataService = new WidgetDataService()

    MyAppExceptionHandler myAppExceptionHandler = new MyAppExceptionHandler()

    Widget getWidgetById(Long widgetId) {
        try {
            List<Widget> widgets = widgetDataService.getAllWidgets()
            widgets.each {
                if(it.id.equals(widgetId)) {
                    return it
                }
            }

            return null
        } catch(MyAppException maExc) {
            log.error(ExceptionUtils.getStackTrace(maExc))
            myAppExceptionHandler.handleOrRethrow(maExc)
        }
    }
}

どうすればこれを達成できるかについてのアイデアはありますか? 純粋な Groovy クロージャが、実行時に内部で Grails がそのサービスに対して行っていることと何らかの形で干渉するのではないかと心配しています (それらはすべて親クラスを明示的に拡張しないクラスであるため)。

4

2 に答える 2

2

これが私のコメントで指摘しようとしていたことです:

package com.example

import groovy.util.logging.Log4j

@Log4j
trait SomeTrait {

    def withErrorHandler(Closure clos) {
        try {
            clos()
        } catch(Exception e) {
            log.error e.message
            throw new ApplicationSpecificException(
                "Application Specific Message: ${e.message}"
            )
        }
    }
}

サービス クラス:

package com.example

class SampleService implements SomeTrait {

    def throwingException() {
        withErrorHandler {
            throw new Exception("I am an exception")
        }
    }

    def notThrowingException() {
        withErrorHandler {
            println "foo bar"
        }
    }
}

テスト:

package com.example

import grails.test.mixin.TestFor
import spock.lang.Specification

@TestFor(SampleService)
class SampleServiceSpec extends Specification {

    void "test something"() {
        when:
        service.throwingException()

        then:
        ApplicationSpecificException e = thrown(ApplicationSpecificException)
        e.message == "Application Specific Message: I am an exception"
    }

    void "test something again"() {
        when:
        service.notThrowingException()

        then:
        notThrown(Exception)
    }
}

これがサンプルアプリです

Grails 3.0.9 でも問題ありません。これは Grails 2.4.* に適用されます。

于 2015-11-02T22:20:04.700 に答える
1

MetaInjection または Spring AOP を使用して、Service クラス メソッドへの呼び出しをインターセプトできます。したがって、各 Service クラスにクロージャーを記述する必要はありません。両方のアプローチを例で説明しているこのブログを見ることができます。

于 2015-10-31T12:53:12.383 に答える