Измените объекты DAO использовать сеттер, а не аргумент конструктора. только .. ick. TenantId является частью требуемого состояния DAO.
Если ваши DAO являются одиночными, я не вижу, как это будет работать (или, по крайней мере, как это можно сделать чисто).
Каков правильный способ сделать это?
IMO, я думаю, что лучший подход должен иметь 1) одноэлементные объекты DAO 2) некоторый тип прокси, который был впрыскивается в DAO, когда они были инстанцированы по HK2, а затем при условии правильного арендатора идентификатора для текущего потока.
я могу думать о двух способах сделать это:
Вариант 1:
Я не пробовал, но я думаю, что вы могли бы, вероятно, впрыснуть UriInfo в ваше DAO,, либо через конструктор, либо в частное поле, либо в сеттер. Вы можете извлечь идентификатор арендатора для текущего запроса из экземпляра UriInfo.
Если бы я был вами, я бы создал абстрактный класс для своих DAO, которые получили UriInfo, введенные в личное поле. Я бы тогда предоставить защищенный метод возвращает текущий арендатор идентификатор из uriInfo.getPathParameters
public abstract class AbstractDao {
// jersey/hk2 provides a proxy that references the current thread-bound request
@Context
private UriInfo info;
protected int getTenantId()
{
// always returns the tenant id for the current request. TODO: add
// logic to handle calls that don't have a tenant id.
return Integer.valueOf(info.getPathParameters.getFirst("tenantId");
}
}
Вариант 2:
?? Другая магия HK2?
Вы можете написать custom injection resolver.
Еще одна идея ...
Вариант 3:
Это один не напрямую ответить на ваш вопрос, так как он не использует HK2 впрыснуть арендатора ID в DAO, но я думаю, это стоит упомянуть.
Вы можете реализовать свой собственный ContainerRequestFilter, который получил идентификатор арендатора и предоставил его другим компонентам вашего приложения.
По умолчанию Джерси будет вызывать фильтр после того, как он разрешит метод ресурса, но до того, как метод будет фактически вызван. Вы можете получить UriInfo с ContainerRequestContext, получить идентификатор пути идентификатора арендатора, а затем передать этот параметр в свою собственную локальную переменную потока. Затем вы можете ссылаться на поток, локальный внутри вашего DAO. Опять же, я рекомендую добавить защищенный метод в базовый класс DAO для инкапсуляции этой логики.
в большинстве моих API вызовов, арендатор параметр пути,
По желанию, вы можете использовать NameBinding контролировать поведение, описанное выше.
Если вы хотите, вы можете реализовать вариант 3, используя обычный ServletFilter.
Примечание:
После того как я написал этот ответ, я понял, что я предположил, что вы были удобными простирающимся ResourceConfig, что вы знали, как получить экземпляр ServiceLocator, и что вы были comfortable with adding your own bindings. Если вы этого не сделаете, дайте мне знать, и я отредактирую свой ответ, чтобы предоставить более подробную информацию.
Джон, спасибо за ответ. DAO не являются синглонами и не будут одиночными, если вы не можете предоставить убедительный аргумент в пользу этого. Вариант 1 не подходит, потому что уровень доступа к данным не должен знать или заботиться о том, чтобы он обслуживал веб-API. Вариант 3 является многопоточным эквивалентом всех уровней, разделяющих статическую переменную. Думаю, я мог бы это сделать. Вариант 2 мог бы работать. Я сейчас воткнулся. Если это то, с чем я иду, я буду отмечать как правильные и уверенные. Еще раз спасибо! –
Звучит как вариант 2 - лучший. Вероятно, вам нужно будет обернуть идентификатор вашего арендатора в классе TenantIdentifier. Попробуйте сделать это, а затем напишите «Factory» и AbstractBinder, который связывает TenantIdentifier с фабрикой. После регистрации связующего, вы должны иметь возможность @Inject экземпляров TenantIdentifier. –
Эрик, любая удача с вариантом 2? Любопытно, как вы решили эту проблему, потому что я делаю что-то подобное в своем проекте. –