首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无法获取Guice方法侦听器的挂起(bindInterceptor期间出现Null指针异常)

无法获取Guice方法侦听器的挂起(bindInterceptor期间出现Null指针异常)
EN

Stack Overflow用户
提问于 2016-09-18 09:53:48
回答 1查看 488关注 0票数 0

我有一个拦截器来限制对任意API的请求。我正在尝试编写一个支持插入TPS值的注释,以便任何方法都可以受到速率限制。

代码语言:javascript
复制
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

    // Permissible transactions per second.
    long tps() default Long.MAX_VALUE;

    // The identifier for the rate limiter. A distinct token bucket is defined
    // per id.
    String id();
}

而拦截器的实现方式如下:

代码语言:javascript
复制
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.isomorphism.util.TokenBucket;
import org.isomorphism.util.TokenBuckets;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * Implementation of the rate limiter.
 */
public class RateLimitMethodAnnotationInterceptor implements    MethodInterceptor {

    private static final ConcurrentHashMap<String, TokenBucket>
            TOKEN_BUCKET_MAP = new ConcurrentHashMap<String,    TokenBucket>();

    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        final RateLimitMethodAnnotation rateLimitMethod =
             methodInvocation.getMethod().getAnnotation(RateLimitMethodAnnotation.class);

        final String rateLimitId = rateLimitMethod.id();
        final long tps = rateLimitMethod.tps();

        boolean proceedMethodCall = tryProceed(rateLimitId, tps);

        while(!proceedMethodCall) {
            Thread.sleep(getDurationTillRefillInMilliSecond(rateLimitId, tps));
            proceedMethodCall = tryProceed(rateLimitId, tps);
        }

        return methodInvocation.proceed();
    }

    private boolean tryProceed(final String tokenBucketId, final long tps) {

        final TokenBucket tokenBucket = TOKEN_BUCKET_MAP.get(tokenBucketId);

        if (tokenBucket == null) {
            TOKEN_BUCKET_MAP.put(tokenBucketId, buildTokenBucket(tps));
        }

        return tokenBucket.tryConsume();
    }

    private long getDurationTillRefillInMilliSecond(final String tokenBucketId, long tps) {
        final TokenBucket tokenBucket = TOKEN_BUCKET_MAP.get(tokenBucketId);

        if (tokenBucket == null) {
            TOKEN_BUCKET_MAP.put(tokenBucketId, buildTokenBucket(tps));
        }

        return   tokenBucket.getDurationUntilNextRefill(TimeUnit.MILLISECONDS);

    }

    private TokenBucket buildTokenBucket(final long tps) {
        return TokenBuckets.builder().withCapacity(tps)
               .withFixedIntervalRefillStrategy(1, 1, TimeUnit.SECONDS)
               .build();
    }
}

现在,为了定义绑定,我使用了以下代码:

代码语言:javascript
复制
import com.google.inject.AbstractModule;
import com.google.inject.matcher.Matchers;

/**
 * Configuration for rate limiting.
 */
public class RateLimitConfig extends AbstractModule {

    public void configure() {
        bindInterceptor(Matchers.any(), 
            Matchers.annotatedWith(RateLimitMethodAnnotation.class),
            new RateLimitMethodAnnotationInterceptor());
    }
}

我写了一个非常简单的健全性测试来证明注入配置是有效的,如下所示:

代码语言:javascript
复制
import org.junit.Test;

import static org.junit.Assert.assertTrue;

/**
 * Rate limit test class.
 */
public class TestRateLimit {

    final int TEST_VAL = 1;

    @Test
    public void testRateLimitInterceptorSanityTest() {
        final RateLimitConfig config = new RateLimitConfig();
        config.configure();

        int retVal = stubMethod();
        assertTrue(retVal == TEST_VAL);
    }

    @RateLimitMethodAnnotation(tps = Long.MAX_VALUE, id="stubMethod")
    public int stubMethod() {
        return TEST_VAL;
    }
}

我最终得到了一个NPE

代码语言:javascript
复制
 Running TestRateLimit
 Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed:   0.073 sec <<< FAILURE!
testRateLimitInterceptorSanityTest(TestRateLimit)  Time elapsed: 0.013 sec  <<< ERROR!
java.lang.NullPointerException
    at com.google.inject.AbstractModule.bindInterceptor(AbstractModule.java:167)
at org.isomorphism.annotation.RateLimitConfig.configure(RateLimitConfig.java:12)
     at org.isomorphism.annotation.TestRateLimit.testRateLimitInterceptorSanityTest(TestRateLimit.java:17)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)

我查看了这里的代码https://github.com/google/guice/blob/master/core/src/com/google/inject/AbstractModule.java,但没有发现任何有用的东西。我调试了代码,但我不能理解数据结构(为了完全理解框架,我必须花几个小时,我不想为简单的任务花时间)。

代码语言:javascript
复制
1. Even for a simple task like this, Guice should not throw an NPE even if 0 methods were annotated with the annotation I have in mind. 
2. Is the configure method never supposed to be called directly in code? If so there is no API given in AbstractModule nor documentation how to configure bindInterceptors. Taking the code out of RateLimitConfig did not work (after putting it into the test suite). 

有人能帮我解决这个问题吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-09-18 15:57:48

您在测试用例中没有创建任何注入器:

代码语言:javascript
复制
@Test
public void testRateLimitInterceptorSanityTest() {
    final RateLimitConfig config = new RateLimitConfig();
    Injector injector = Guice.createInjector(config);
    TestRateLimit testInstance = injector.getInstance(TestRateLimit.class);

    int retVal = testInstance.stubMethod();
    assertTrue(retVal == TEST_VAL);
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39553338

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档