3

私は春が大好きです。しかし、メソッド実行の前後にコードを挿入することになると、Spring/AOP が間違っていたことを認めざるを得ません。

私の謙虚な意見では、メソッド名またはメソッド名に似た正規表現をハードコーディングすることは、私たちがこれまでに経験した最後のことであるべきです。私たちは皆、2000 年代初頭の XML 地獄から苦労してそれを学びました。

対照的に、EJB3 のインターセプターはアノテーション ベースで、シンプルで読みやすく、すべてではないにしてもほとんどの問題に対処できます。Spring で EJB3 スタイルのインターセプターをコーディングできたらいいと思いませんか?

私が知っている最善の解決策は@annotation、次のコードで行ったように、ポイントカット式で使用することです。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AroundExecution {

}

@Component
public class SimpleBean {
    @AroundExecution
    public void printGreetings(){
        logger.info("Hello World 2");
    }
}

@Aspect
@Component
public class SimpleAdvice {
    @Around("@annotation(com.myinterceptors.springaop.AroundExecution)")
    public Object adviceAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object retVal = null;
        try {
            logger.info("Before executing");
            retVal = joinPoint.proceed();
            logger.info("After executing");
        } 
        catch(Throwable e) {
            logger.error("Execution error");
            throw e;
        }
        return retVal;
    }
}

注釈クラス名のハードコーディングの最後のビットを削除することは不可能のようです。

Guice を使用していた場合、次のようなことができます。

    public class SimpleModule extends AbstractModule {
        protected void configure() {
        AroundInterceptor interceptor = new AroundInterceptor();
        bindInterceptor(
            Matchers.any(), 
            Matchers.annotatedWith(BeforeExecution.class).or(Matchers.annotatedWith(AfterExecution.class)), 
            interceptor
        );
        }
    }

public class AroundInterceptor implements MethodInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(AroundInterceptor.class);

    public Object invoke(MethodInvocation invocation) throws Throwable {

        try{
            if(invocation.getMethod().getAnnotation(BeforeExecution.class)!=null){
                invokeBefore(invocation);
            }
            return invocation.proceed();
        }
        finally{
            if(invocation.getMethod().getAnnotation(AfterExecution.class)!=null){
                invokeAfter(invocation);
            }
        }
    }

    protected void invokeBefore(MethodInvocation invocation) throws Throwable {
        logger.info("Intercepted before executing: "+invocation.getMethod().getName());
    }


    protected void invokeAfter(MethodInvocation invocation) throws Throwable {
        logger.info("Intercepted after executing: "+invocation.getThis().getClass().getName()+"."+
                invocation.getMethod().getName());
    }
}

正確には最も美しいとは言えませんが、それは仕事を成し遂げます.

デコレータ パターンは別の方法ですが、メンテナンスに多くのオーバーヘッドが追加されます。

Spring Bean 用の JSR-299 CDI デコレーター

Spring がポイントカット式の拡張を許可して、クラス定義をパラメーターとしてサポートできるようにすると、はるかに簡単になります。@Around("@annotatedWith", MyAnnotation.class)

メタデータまたはアプリケーション コンテキストでのハード コーディングを必要としないインターセプターを Spring に実装したことがある人がいるだろうか?

4

1 に答える 1

0

少し遅れていますが、Spring の公式ドキュメントで次のコードを見てください。

@Before("com.xyz.lib.Pointcuts.anyPublicMethod() && @annotation(auditable)")
public void audit(Auditable auditable) {
    AuditCode code = auditable.value();
    // ...
}

ポイントカットで参照されている監査可能な引数名に注意してください。

@Around アドバイスを使用する場合は、コードを次のように変更するだけです。

@Around("com.xyz.lib.Pointcuts.anyPublicMethod() && @annotation(auditable)")
public void audit(ProceedingJoinPoint joinPoint, Auditable auditable) {
    AuditCode code = auditable.value();
    // ...
}
于 2016-01-07T10:08:25.367 に答える