Ответ 1
Вместо A
и B
установите Common
, имейте их requireBinding()
для классов, которые им нужны из Common
. Затем модули, которые полагаются на A
или B
, также должны установить Common
. Это может показаться немного странным, но это действительно желательно, поскольку A
и B
теперь менее тесно связаны с Common
.
Обновление
Причина, по которой я устанавливаю два
ShiroWebModule
, заключается в том, что я хочу, чтобы ресурсы Джерси в модулеui
были защищены только с помощью одной конфигурации Shiro (которая не требует защиты паролем ресурсов), а все ресурсы Джерси вapi
должен быть защищен с использованием совершенно другой конфигурации Shiro (той, которая понимает только токены-носители в качестве механизма аутентификации).
В широком смысле это невозможно. Guice Injector
предоставляет один способ сделать что-то (как правило, одну реализацию интерфейса) для всего приложения; не разные механизмы для каждой упаковки. Ваши два Module
s, SwsApiServletModule
и SwsUiServletModule
предоставляют несколько идентичных привязок, а SwsModule
устанавливает их оба вместе. В сущности, вы говорите "Guice, пожалуйста, предоставьте механизм аутентификации на основе токена", а затем сразу после "Guice, пожалуйста, предоставьте механизм аутентификации на основе пароля". Он может делать только один или другой, поэтому вместо того, чтобы выбирать один произвольно, он не работает быстро.
Конечно, существует ряд решений, в зависимости от ваших потребностей. Наиболее распространенным является использование привязки аннотаций и для запроса пользовательского интерфейса и кода API различной аннотации. Таким образом, вы можете установить две разные реализации (с разными аннотациями) одного и того же интерфейса или класса.
Вот пример:
package api;
public class ApiResources {
@Inject
public ApiResources(@ApiAuthMechanism AuthMechanism auth) {
this.auth = auth;
}
}
---
package api;
public class ApiModule implements Module {
public void configure() {
bind(AuthMechanism.class).annotatedWith(ApiAuthMechanism.class)
.to(BearerTokenAuthMechanism.class);
}
}
---
package ui;
public class UiResources {
@Inject
public UiResources(@UiAuthMechanism AuthMechanism auth) {
this.auth = auth;
}
}
---
package ui;
public class UiModule implements Module {
public void configure() {
bind(AuthMechanism.class).annotatedWith(UiAuthMechanism.class)
.to(PasswordAuthMechanism.class);
}
}
---
package webap;
public class WebappModule implements Module {
public void configure() {
// These modules can be installed together,
// because they don't install overlapping bindings
install(new ApiModule());
install(new UiModule());
}
}
Вы отмечаете в комментарии, что у вас нет контроля над наложенными связями, которые устанавливаются, потому что они поступают из стороннего модуля. Если это так (я не видел, где это происходит в вашем коде), возможно, третья сторона не хочет, чтобы вы делали то, что вы пытаетесь сделать, из соображений безопасности. Например, просто привязка механизма, основанного на пароле, может привести к уязвимости во всем приложении. Возможно, стоит попытаться лучше понять, как третья сторона намерена использовать свои модули.
Другим вариантом, который не идеален, но может работать в некоторых случаях использования, является использование двух полностью изолированных экземпляров Injector
, по одному с каждой привязкой. Затем вы вручную передаете экземпляры, необходимые для кода пользовательского интерфейса и API. Это несколько поражает цель Гиса, но это не всегда неправильное решение. Использование child Injector
s может сделать это менее болезненным.
В стороне, ваш "образец кода" огромен, и, вероятно, более 90% не связано с проблемой. В будущем, пожалуйста, найдите время, чтобы создать SSCCE, который содержит только код, имеющий отношение к проблеме. Просто никто не собирается просеивать более 100 Java файлов и 7,300+ строк кода, чтобы понять вашу проблему. Это не только облегчит людям, которые пытаются вам помочь, но просто попытка создать SSCCE, который демонстрирует проблему, часто будет достаточно, чтобы помочь вам понять и решить ее самостоятельно.