Начиная с версии 3.1, среда Spring предлагает абстракцию к нескольким различным источникам, с помощью которых вы можете легко настроить свое приложение: Environment
.
В этой статье я опишу микропроцессор, который я выполнил, чтобы доказать, что, хотя это удобный API, если вы используете Spring в своем приложении, он может привести к снижению производительности, из-за которого вы не должны использовать его вне кода инициализации.
Как это работает
Прежде чем перейти к цифрам, сделайте небольшое экскурс по внутренностям Environment
, которые важны для этого поста.
Из документации:
Свойства играют важную роль практически во всех приложениях и могут быть получены из различных источников: файлов свойств, системных свойств JVM, системных переменных среды, JNDI, параметров контекста сервлета, специальных объектов свойств, карт и т. Д. Роль объекта среды по отношению к свойствам заключается в предоставлении пользователю удобного служебного интерфейса для настройки источников свойств и разрешения свойств из них.
Таким образом, вы можете использовать Environment
чтобы иметь общий интерфейс к свойствам, предоставляемым с различными стратегиями, используя простой вызов getProperty
для доступа к требуемому значению. Посмотрите на следующий Groovy код:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
@Component public class Greeter { private Environment environment @Autowired public Greeter greeter(Environment environment){ this .environment = environment } def nickName(user) { environment.getProperty( "user" ) // here be magic } def greet(user) { def nick = nickName(user) if (name == null ) println "Hi, ${user}!" else println "Hi, ${nick}!" } } |
Теперь я могу указать псевдонимы в файле свойств, чтобы я мог приветствовать знакомых пользователей с более знакомым псевдонимом, при этом имея возможность приветствовать также пользователей, которым не дали ни одного псевдонима. Аккуратно, но как насчет производительности?
Теперь я могу указать псевдонимы в файле свойств, чтобы я мог приветствовать знакомых пользователей с более знакомым псевдонимом, при этом имея возможность приветствовать также пользователей, которым не дали ни одного псевдонима. Аккуратно, но как насчет производительности?
Скрытое Исключение
Я попал в это упражнение во время отладки нескольких медленных страниц на веб-сайте, над которым я работаю: целевые страницы основного сайта KLM. Хотя производительность в целом удовлетворительная, две страницы постоянно давали время ответа выше второго. Определенно слишком много .
В нашем коде мы переводили названия некоторых стран в запрашиваемые ключи для внешних служб. Нам также нужно было переопределить простой алгоритм преобразования с очень конкретными исключениями из правила. Фактический код был в значительной степени похож на приведенный выше Greeter.greet(user)
, и сессия Flight Recorder в итоге предоставила нам узкое место в производительности (нажмите, чтобы открыть):
Для обновления 12 страниц мы молча выдавали 140k + исключений. И исключения являются sloooooow , даже если вы просто создаете их.
Глядя на верхнее исключение, было довольно легко понять, что происходит: Environment
проверяет, определено ли запрошенное свойство в текущем контексте JNDI. Но если имя не найдено, NameNotFoundException
. В нашем конкретном случае мы использовали поиск свойств для исключительных случаев, что означает, что подавляющее большинство случаев приводило к исключению.
Микро тест
Я собрал микропроцессор для оценки потенциального прироста производительности исходной стратегии поиска свойств по сравнению с более простым, когда соответствующие свойства загружаются во время создания класса. Я использовал Java Microbenchmark Harness , который делает невероятную работу по упрощению микропроцессорных тестов на JVM: JIT, прогрев, загрузка классов, все позаботились о вас, и вы можете просто пойти дальше и проверить свой код. Вот результаты (чем выше цифры, тем лучше):
[Поиск недвижимости за вызов]
Результат: 28917,876? (99,9%) 183,630 операций / с [Среднее] Статистика: (min, avg, max) = (25688.067, 28917.876, 30976.876), stdev = 777.500
Доверительный интервал (99,9%): [28734.246, 29101.505]
[Загрузка имущества при строительстве класса]
Результат: 159062,900? (99,9%) 1013,309 операций / с [Среднее] Статистика: (min, avg, max) = (138707.926, 159062.900, 177183.549), stdev = 4290.413
Доверительный интервал (99,9%): [158049.591, 160076.209]
Как и ожидалось, в пять раз быстрее.
Выводы
Я не большой поклонник Spring, но если вы используете его, класс Environment
— это очень простой интерфейс для конфигурации вашего приложения. Но если вы не используете JNDI в качестве основного хранилища свойств конфигурации, его характеристики производительности делают его отличным инструментом только в том случае, если вы используете его в коде инициализации, а не во время онлайновой обработки запросов.
Ссылка: | Spring Environment предназначен для кода инициализации только от нашего партнера по JCG Карло Скиоллы из блога Skuro . |