Должен ли сервисный уровень перехватывать все исключения dao и переносить их в исключения сервиса?

23

У меня есть три слоя Spring веб-приложение: дао, сервис и контроллеры. Контроллер никогда не вызывает напрямую dao, он делает это через уровень сервиса. Прямо сейчас, в большинстве случаев, если есть исключение dao (время выполнения), которое не обрабатывается, оно будет перехвачено JSP, показывающим сообщение об ошибке конечному пользователю. Должен ли сервисный уровень перехватывать все исключения dao и переносить их в исключения сервиса?

try {
   daoInstance.someDaoMethod();
} catch(DataAccessException dae) {
   throw new ServiceException("message", dae);
}

Предположим, что ServiceException также является средой выполнения и не обрабатывается. Есть ли какая-либо разница, чтобы просто генерировать исключение DataAccessException вместо ServiceException? Я просто подумал, что уровень представления не должен знать об исключении доступа к данным. Но я не вижу смысла в обнаружении неисправимых исключений, просто чтобы их обернуть.

Оскар
источник

Ответы:

18

Я думаю, что важным фактором является то, кто ваши клиенты обслуживания.

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

Тем не менее, для общедоступного кода; сервис, который потребляется третьей стороной или клиентом, я думаю, что лучше обернуть любые неконтролируемые исключения в сервис-ориентированное исключение, в первую очередь из соображений безопасности, во-вторых, для слабой связи и чистой абстракции.

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

Внешний клиент службы не имеет отношения к деталям вашей реализации и в любом случае не может обрабатывать непроверенные исключения, так как они являются ошибками или проблемами окружающей среды. В защищенных приложениях ошибки базы данных просто недостаточно безопасны для распространения, OracleException - ORA-01234 - ...это может быть третья вставленная таблица. Клиенту должно быть разрешено иметь дело с любыми проверенными / ожидаемыми исключениями, которые он может обработать, и рассматривать все остальное как сообщение о потенциальной ошибке. Ваш сервисный контракт должен быть атомарной, последовательной, транзакционной абстракцией. Если он ничего не может сделать с исключением, то единственное, что остается сделать - это сообщить об ошибке, У вас уже есть возможность записать исключение, так зачем обременять вашего конечного пользователя деталями? Ваше приложение может отслеживаться, поэтому вы уже знаете о непроверенных исключениях, прежде чем пользователи сообщат о них.

Никогда нельзя употреблять исключения, и я не фанат проверенных исключений, но я предпочитаю иметь план, соответствующий характеру всего продукта.

codenheim
источник
13

Нет, вы не должны помещать исключения DAO в веб-приложение.

В коде много шума для нулевой выгоды. Исключения DAO являются непроверенными исключениями по уважительной причине. Код приложения не может сделать ничего полезного для восстановления после исключения DAO. Настоящая проблема здесь:

... он будет перехвачен JSP, показывающим сообщение об ошибке конечному пользователю.

Исправьте эту проблему в одном месте, вместо того, чтобы разбирать всю кодовую базу.

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

NB: если вы пишете много утомительного кода, например, создаете кучу блоков catch, которые просто переносят и перебрасывают, почти всегда есть лучшее решение.

Кевин Клайн
источник
Спасибо за Ваш ответ. И да, JSP показывает пользовательское сообщение: «Ой, что-то пошло не так». Он не показывает никакой информации об исключении
Оскар
7

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

  • Согласованность: объявленные исключения агрегируются к вершине стека вызовов. Если вы не переносите исключения, а вместо этого передаете их, объявляя свои методы для их выброса, вы можете получить методы верхнего уровня, которые объявляют множество различных исключений. Объявление всех этих исключений в каждом методе резервного копирования стека вызовов становится утомительным.

  • Инкапсуляция. Возможно, вы не хотите, чтобы ваши компоненты верхнего уровня знали что-либо о компонентах нижнего уровня или об исключениях, которые они выдают. Например, целью интерфейсов и реализаций DAO является абстрагирование деталей доступа к данным от остальной части приложения. Теперь, если ваши методы DAO выдают SQLException, тогда код, использующий DAO, должен их перехватить. Что если вы перейдете к реализации, которая считывает данные из веб-службы, а не из базы данных? Тогда вам, DAO-методам, придется выдавать и RemoteException, и SQLException. И, если у вас есть DAO, которая читает данные из файла, вам нужно будет также выбросить IOException. Это три разных исключения, каждое из которых связано с собственной реализацией DAO.

Короче говоря, ответ - да!

fabienbk
источник
3
Реализации JPA (например, Hibernate) генерируют непроверенные исключения. Они не должны быть объявлены или пойманы.
Кевин Клайн