Порядок впрыскивания "MembersInjector" и обычного "метода" - неправильный впрыск? - PullRequest
0 голосов
/ 18 января 2019

Я пользуюсь google-guice уже пару дней, и меня это все больше впечатляет.

Я создал MemberInjector для простой интеграции каркаса ведения журнала SLF4J, просто с дополнительной аннотацией. Это означает, что вместо использования всегда долгосрочного:

private static final Logger LOG = LoggerFactory.getLogger(MyClass.class);

Я сейчас просто использую:

@Log
Logger LOG;

Это действительно здорово, НО:
Я также использую метод-инъекцию как своего рода начальную функцию в том же классе, и если я получу доступ к экземпляру LOG, это вызовет NPE! Потому что он еще не введен.

@Inject
public void start() { 
    //And here is the problem...
    LOG.info("in start")  //causes NPE, cause LOG is not injected yet
}

Если я использую экземпляр LOG в другом (не внедренном) методе, он работает отлично,

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

Спасибо за любую подсказку.

1 Ответ

0 голосов
/ 08 февраля 2019

Одним из решений, которое я нашел, было создание просто дополнительного слушателя, который ищет определенный метод, такой как ("init" или "start"), и просто вызывает его после создания и внедрения членов.

См. В модулеконфигурация:

@Override
protected void configure() {
    bindListener(Matchers.any(), new InitMethodTypeListener());
    //...

InitMethodTypeListener:

public class InitMethodTypeListener implements TypeListener {

    private static final Logger log = LoggerFactory.getLogger(InitMethodTypeListener.class);

    @SuppressWarnings("rawtypes")
    static class InitInvoker implements InjectionListener {
        @Override
        public void afterInjection(final Object injectee) {
            try {
                log.info("Invoke init() from Class: {}", injectee.getClass().getName());
                injectee.getClass().getMethod("init").invoke(injectee);
            } catch (final Exception e) {
                log.error(e.getMessage(), e);
            }
        }

        public static final InitInvoker INSTANCE = new InitInvoker();
    }

    @SuppressWarnings("unchecked")
    @Override
    public <I> void hear(final TypeLiteral<I> type, final TypeEncounter<I> encounter) {

        try {
            if (type.getRawType().getMethod("init") != null) {
                encounter.register(InitInvoker.INSTANCE);
            }
        } catch (final NoSuchMethodException | SecurityException e) {
            // do nothing here, if not init-method found - no call
        }
    }
}

Возможно, это не прямой путь, но он работает.И поэтому я уверен, что все члены правильно вводятся при вызове init-метода.

В этой реализации все объекты, находящиеся под контролем, их «init» -метод будет вызываться автоматически после создания и внедрения объекта.

...