Как связать перехватчик метода с провайдером?

Есть ли способ привязать перехватчик метода к провайдеру, а не к экземпляру?

например. Я использую код ниже, чтобы связать перехватчики, как бы привязать INTERCEPTOR к провайдеру, а затем к аннотации?

bindInterceptor(
    Matchers.any(), Matchers.annotatedWith(ANNOTATION.class), new INTERCEPTOR());

Ответ 1

Guice не разрешает AOP для экземпляров, не созданных Guice: Ограничения AOP в Guice

"Экземпляры должны быть созданы Guice конструктором @Inject-annotated или no-argument"

Это означает, что экземпляры, созданные с поставщиком, не будут кандидатами для АОП.

С другой стороны, до тех пор, пока ваш провайдер будет создан Guice в соответствии с указанными условиями, ваш поставщик может быть кандидатом на АОП.

Вот пример, который демонстрирует это:

AOP Аннотация:

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

Provider:

public class ExampleProvider implements Provider<Example> {

    @AOPExample
    public Example get() {
        System.out.println("Building...");
        return new Example();
    }
}

Целевой пример:

public class Example {

    @AOPExample
    public void tryMe() {
        System.out.println("example working...");
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

Модуль:

public class ExampleModule extends AbstractModule {
    @Override
    protected void configure() {
        bindInterceptor(Matchers.any(), Matchers.annotatedWith(AOPExample.class), new LoggingAOP());

        bind(Example.class).toProvider(ExampleProvider.class);
    }
}

Тестовый код:

public class Test {

    public static void main(String[] args) {
        Injector injector = Guice.createInjector(new TestModule());

        ExampleProvider exampleProvider = injector.getInstance(ExampleProvider.class);
        Example example = exampleProvider.get();

        example.tryMe();

        Example directExample = injector.getInstance(Example.class);

        directExample.tryMe();

    }
}

Выход теста:

start
Building...
end took: 3
example working...
start
Building...
end took: 0
example working...

Обратите внимание, что "пример работы..." не окружен кодом таймера. Однако Provider.get( "Создать..." ).

Если ваш вопрос: может ли перехватчик (новый INTERCEPTOR()) быть предоставлен через поставщика Guice, ответ - нет. Самое близкое, что вы можете получить к этой функции, вызывает метод requestInjection() в модуле configure. Это введет ваш Interceptor с соответствующим кодом. Из вашего перехватчика вы можете использовать Провайдеры, чтобы избежать каких-либо накладных расходов, которые вызывают медленность во время запуска.

Вот что я имею в виду:

Модуль:

public class TestModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(String.class).toInstance("One");
        bind(String.class).annotatedWith(Names.named("two")).toInstance("Two");

        LoggingAOP loggingAOP = new LoggingAOP();

        bindInterceptor(Matchers.any(), Matchers.annotatedWith(AOPExample.class), loggingAOP);

        requestInjection(loggingAOP);

        bind(Example.class).toProvider(ExampleProvider.class);
    }
}

перехватчик:

public class LoggingAOP implements MethodInterceptor {

    @Inject
    private Provider<SomethingThatTakesALongTimeToInit> provider;

    public Object invoke(MethodInvocation invocation) throws Throwable {
        provider.get()...
        System.out.println("start");
        long start = System.currentTimeMillis();
        Object value =  invocation.proceed();
        System.out.println("end took: " + (System.currentTimeMillis() - start));
        return value;
    }
}

Надеюсь, это ответит на ваш вопрос.