Статьи

JSR-299 & @Produces

Я читал JSR-299 и у меня есть несколько мыслей.

Во-первых, цитата из главы 1:

«Использование этих сервисов значительно упрощает задачу создания приложений Java EE путем интеграции веб-уровня Java EE с корпоративными сервисами Java EE. В частности, компоненты EJB могут использоваться как управляемые компоненты JSF, таким образом интеграция моделей программирования EJB и JSF. «

Второе предложение заставило мои уши заколотиться. Действительно ли я хочу, чтобы EJB-компоненты были бэк-бинами веб-страниц? Для меня это звучит как перепутывание обязанностей в MVC. Конечно, есть люди, которые говорят, что контроллер MVC должен быть худым, а модель — толстой ( реклама на YouTube).). Возможно, я старая школа, но я предпочитаю, чтобы на моей странице JSF был вспомогательный компонент, который является моделью моего представления и имеет дело с конкретной логикой представления, а когда ему требуется поддержка транзакций и безопасности, он может вызывать EJB, который имеет дело с более деловые вещи.

Затем JSR вводит аннотацию @Produces. Мне не нравится эта аннотация, и остальная часть этой публикации блога о том, почему.

Когда мне нужен объект, такой как служба или ресурс, я могу заставить контейнер внедрить его для меня. Обычно я использую аннотации @Inject, @EJB, @Resource или @PersistenceContext. В объект, которому вводят такие вещи, я могу написать код, который использует эти объекты. Я позволил контейнеру составить мой объект, используя эти части и другие компоненты. Есть много преимуществ, таких как наличие кода, который легко тестируется, потому что я могу составить объект из макетов, если требуется, или возможность конфигурировать его композицию, а не жестко кодировать его. И мы все привыкли создавать такие объекты с самых первых дней весны, если не раньше.

Теперь, с @Produces, у нас есть новый способ заявить, откуда все происходит. Возьмите пример в JSR, где показан компонент Login (глава 1). Компонент Login «производит» текущего пользователя (стр. 4). Хорошо, давайте начнем с некоторого кода:

    @Produces @LoggedIn User getCurrentUser()

Если я читаю этот код вслух, я говорю что-то похожее на: «Компонент с именем Login создает текущего зарегистрированного пользователя».

Что ж, для меня это не имеет особого смысла, потому что, если исходить из дизайна с чисто ОО точки зрения, начиная с вариантов использования, в сценарии использования не упоминается компонент входа в систему, и даже если бы он был, не «производит» пользователя! Пользователь существует до того, как он войдет в программу. Они просто аутентифицируются и, возможно, авторизуются после входа в систему. Компонент входа в систему программного обеспечения (который может быть представлен компонентом Login) может предоставить подробную информацию о зарегистрированном в данный момент пользователе. Синтаксис, использованный в этом коде выше, на мой взгляд, имеет плохое семантическое значение.

Так что, если это современный модный способ передачи информации в приложении JSF, я должен спросить себя, не могли ли мы делать такие вещи в прошлом? Или было действительно сложно программировать до того, как появилась аннотация @Produces? Давайте посмотрим на одно решение; некоторый код в бине, который должен знать вошедшего в систему пользователя.

    @Inject Login loginBean;

Чтобы использовать это, компонент Login должен быть объявлен как @SessionScoped, и угадайте, что — это уже отмечено в примере JSR.

Чтобы получить доступ к текущему пользователю, я бы просто написал такой код:

    loginBean.getCurrentUser().getName() blah blah

Просто да?

Если вам не нравится идея внедрения bean-компонента Login, то почему бы просто не создать bean-объект сессионной области с именем «CurrentUser» и во время входа в систему установить атрибуты аутентифицированного пользователя в этот bean-объект сессионной области? Зачем прибегать к дополнительным способам добавления объектов, а именно к аннотации @Produces? Поскольку существует другой способ сделать инъекцию, весь механизм стал более сложным. Я полагаю, что именно эти типы сложности заставляют новичков отказаться от Java EE, прежде чем они полностью поймут это, и которые заставляют существующих сторонников Java сдаться и перейти к Grails и т. Д.

Чтобы перейти к аннотации @Produces, нам даны квалификаторы. Классификаторы — это эффективные типы безопасных имен, используемые для фильтрации, и поэтому они лучше, чем константы String в интерфейсе, где-то используемом в сочетании с аннотацией @Named. Вот почему я не думаю, что квалификаторы должны использоваться как норма, а скорее как исключение. Класс вводимого объекта должен иметь подходящее имя, чтобы сообщить читателю, что происходит. Рассмотрим этот код, который внедряет текущего пользователя, которого создает бин входа в систему:

    @Inject @LoggedIn User currentUser;

В этой строке происходит ненужная тройня. «LoggedIn», «User» и «currentUser». В идеальном мире я не хочу здесь три имени, я хочу одно. Java вынуждает меня объявлять тип, который на самом деле не так уж необходим, потому что компилятор может, используя соглашения, выводить тип по имени. Но давайте не будем идти туда, а вместо этого примем, что мы должны объявить тип. Почему же тогда я хочу дополнительно объявить классификатор? Я не, это пустая трата энергии пальцев. Только при наличии двусмысленности я буду вынужден использовать классификатор. Но если бы у меня была модель сессий, в которой содержался пользователь, я мог бы сэкономить энергию, используя квалификатор. Я бы просто ввел модельный компонент и вытащил из него текущего пользователя.Это то, чем я занимаюсь годами без проблем. Моя мама всегда говорила мне не чинить то, что не сломано.

В этом руководстве по началу работы с JBoss они приводят пример создания случайного числа с кодом, подобным следующему (у производителя):

    @Produces @Random int next() {
        return getRandom().nextInt(maxNumber - 1) + 1;
    }

и этот код у потребителя:

    @Inject @Random int someRandomNumber;

Конечно, это игрушечный пример. Но что плохого в том, чтобы внедрить bean-компонент Generator (который содержит этот метод-производитель) и вызвать метод, который генерирует случайное число? Я мог бы даже работать с @Alternative, если бы я хотел принять решение о реальной реализации во время развертывания.

Для меня очень важно ввести боб, а не значение, чтобы его было удобнее читать. Он предоставляет читателю (сопровождающему) контекстную информацию о том, откуда взялась эта ценность. На мой взгляд, следующий код намного лучше. Это быстрее написать, потому что мне не нужно создавать аннотацию квалификатора.

    @Inject Generator generator;

И затем в этом классе, некоторый код для использования генератора:

    generator.nextRandomInt();

В разделе 1.3.3 JSR приведен пример настройки менеджеров сущностей для внедрения в bean-компоненты:

    @Produces @PersistenceContext(unitName="UserData") @Users
    EntityManager userDatabaseEntityManager;

И затем вот код, который использует этот менеджер сущностей:

    @Inject @Users EntityManager userDatabaseEntityManager;

О, и не забудьте код для аннотации @Users … В итоге у меня появятся два дополнительных файла (аннотация и продюсер). Действительно ли весь этот код лучше, чем следующий, который просто помещается в компонент, требующий менеджера сущностей:

    @PersistenceContext(unitName=Units.UserData)
    EntityManager userDatabaseEntityManager;

Я просто не уверен, что «современный» и модный, но сложный способ сделать это лучше с помощью JSR-299.

Затем в разделе 3.3 мы расскажем немного больше о том, почему существуют производители и при каких обстоятельствах мы можем их использовать:

— объекты, которые нужно внедрить, не обязательно должны быть экземплярами bean-компонентов

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

— конкретный тип

вводимых объектов может изменяться во время выполнения. Это именно то, для чего нужны аннотации @Alternative и @Specialize, и мне не нужно использовать производителя для изменения конкретной реализации времени выполнения.

— объекты требуют некоторой пользовательской инициализации, которая не выполняется конструктором бина

Добавление аннотации @Inject в конструктор сообщает контейнеру, какой конструктор вызывать, когда требуется специальная конструкция. Как производитель может производить то, чего не может боб?

Затем в разделе 3.4.2 говорится об объявлении полей производителя. В приведенном ими примере показано поле с видимостью по умолчанию (пакета), но, насколько я могу судить, любой компонент в комплекте развертывания, даже один вне пакета производителей, может использовать «продукт». Это немного похоже на непристойное нападение на Java.

Подводя итог, я думаю, я просто хочу обратиться к будущим авторам спецификаций. Если вы не можете найти способ сделать что-то просто, особенно если у нас уже есть этот механизм, пожалуйста, не идите и не усложняйте вещи, чем они должны быть. Я не хочу изучать 92 страницы JSR просто для того, чтобы хорошо использовать бины, когда мне уже нужно изучать тысячи других страниц JSR только для того, чтобы начать работать с Java EE.
 

От http://blog.maxant.co.uk/pebble/2011/11/07/1320702240000.html