Допустимо ли для вас кодировать каждую операцию сервера, как показано ниже?
void op1(String username, ...)
{
String userScope = getConfigurationScopeForUser(username);
String language = cfg.lookupString(userScope, "language");
int fontSize = cfg.lookupInt(userScope, "font_size");
... // business logic expressed in terms of language and fontSize
}
(Приведенный выше псевдокод предполагает, что имя пользователя передается в качестве параметра, но вы можете передать его через другой механизм, например, локальное хранилище потока.)
Если вышеуказанное приемлемо, то Config4 * может удовлетворить ваши требования. Используя Config4 *, метод getConfigurationScopeForUser()
, используемый в приведенном выше псевдокоде, может быть реализован следующим образом (предполагается, что cfg
является объектом конфигурации, который был ранее инициализирован путем анализа файла конфигурации):
String getConfigurationScopeForUser(String username)
{
if (cfg.type("user", username) == Configuration.CFG_SCOPE) {
return Configuration.mergeNames("user", username);
} else {
return "user.default";
}
}
Вот пример файла конфигурации для работы с вышеуказанным. Большинство пользователей получают свою конфигурацию из области "user.default", но Мэри и Джон имеют свои собственные переопределения некоторых из этих значений по умолчанию:
user.default {
language = "English";
font_size = "12";
# ... many other configuration settings
}
user.John {
@copyFrom "user.default";
language = "Klingon"; # override a default value
}
user.Mary {
@copyFrom "user.default";
font_size = "18"; # override a default value
}
Если приведенное выше звучит так, как будто это соответствует вашим потребностям, я предлагаю вам прочитать главы 2 и 3 «Руководства по началу работы», чтобы получить достаточно хорошее понимание синтаксиса и API Config4 *, чтобы иметь возможность подтвердить / опровергнуть пригодность Config4 * для ваших нужд. Вы можете найти эту документацию на веб-сайте Config4 * .
Отказ от ответственности: я сопровождаю Config4 *.
Изменить: я предоставляю более подробную информацию в ответ на комментарии bacar.
Я не помещал Config4 * в репозиторий Maven. Однако собрать Config4 * с помощью связанного файла сборки Ant тривиально, потому что Config4 * не имеет никаких зависимостей от сторонних библиотек.
Другой подход к использованию Config4 * в серверном приложении (подсказанный комментарием bacar) с Config4 * следующий ...
Реализуйте каждую операцию сервера, как в следующем псевдокоде:
void op1(String username, ...)
{
Configuration cfg = getConfigurationForUser(username);
String language = cfg.lookupString("settings", "language");
int fontSize = cfg.lookupInt("settings", "font_size");
... // business logic expressed in terms of language and fontSize
}
Использованный выше метод getConfigurationForUser()
может быть реализован, как показано в следующем псевдокоде:
HashMap<String,Configuration> map = new HashMap<String,Configuration>();
synchronized String getConfigurationForUser(String username)
{
Configuration cfg = map.get(username);
if (cfg == null) {
// Create a config object tailored for the user & add to the map
cfg = Configuration.create();
cfg.insertString("", "user", username); // in global scope
cfg.parse("/path/to/file.cfg");
map.put(username, cfg);
}
return cfg;
}
Вот пример файла конфигурации для работы с вышеуказанным.
user ?= ""; // will be set via insertString()
settings {
@if (user @in ["John", "Sam", "Jane"]) {
language = "Klingon";
} @else {
language = "English";
}
@if (user == "Mary") {
font_size = "12";
} @else {
font_size = "10";
}
... # many other configuration settings
}
Основные комментарии, которые у меня есть по поводу двух подходов, заключаются в следующем:
Первый подход (один Configuration
объект, содержащий множество переменных и областей видимости), вероятно, потребует немного меньше памяти, чем второй подход (много Configuration
объектов, каждый с небольшим количеством переменных). Но я предполагаю, что использование памяти при любом подходе будет измеряться в килобайтах или десятках килобайт, и это будет незначительно по сравнению с общим объемом памяти вашего серверного приложения.
Я предпочитаю первый подход, потому что один объект Configuration
инициализируется только один раз, а затем к нему осуществляется доступ через операции в стиле lookup()
только для чтения. Это означает, что вам не нужно беспокоиться о синхронизации доступа к объекту Configuration
, даже если ваше серверное приложение является многопоточным. Напротив, второй подход требует, чтобы вы синхронизировали доступ к HashMap
, если ваше серверное приложение является многопоточным.
Накладные расходы на операцию в стиле lookup()
составляют, скажем, наносекунды или микросекунды, в то время как накладные расходы на синтаксический анализ файла конфигурации составляют, скажем, миллисекунды или десятки миллисекунд (в зависимости от размера файла). . Первый подход выполняет этот относительно дорогой анализ файла конфигурации только один раз, и это делается при инициализации приложения. Напротив, второй подход выполняет этот относительно дорогой анализ файла конфигурации «N» раз (один раз для каждого из «N» пользователей), и эти повторяющиеся расходы возникают, пока сервер обрабатывает запросы от клиентов. Это снижение производительности может быть или не быть проблемой для вашего приложения.
Я считаю, что простота использования важнее, чем простота реализации. Итак, если вы чувствуете, что второй подход упростит обслуживание файла конфигурации, я предлагаю вам использовать этот подход.
При втором подходе вы можете задаться вопросом, почему я поместил большинство переменных в именованную область видимости (settings
), а не в глобальную область видимости вместе с «введенной» переменной user
. Я сделал это по причине, выходящей за рамки вашего вопроса: разделение «внедренных» переменных от переменных, видимых для приложения, упрощает выполнение проверки схемы для переменных, видимых для приложения.
person
Community
schedule
16.05.2012