Можно ли использовать объекты @Service в качестве @Controllers?

#spring #spring-mvc

#spring #spring-mvc

Вопрос:

У меня есть сервер, который в основном обслуживает JSON API. В настоящее время у нас есть @Controllers, которые прямолинейно делегируют конечные точки REST методам в классах @Service.

Это приводит к большому количеству ненужного шаблонного кода. Могу ли я столкнуться с проблемами, если я просто прокомментирую свои классы @Service аннотациями @Controller и @RequestMapping (например, испорчу вызовы транзакций? Проблемы с зависимостями между службами?)

Ответ №1:

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

Это происходит потому, что @Controller обычно загружаются в дочернем контексте (сервлет диспетчера).

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

РЕДАКТИРОВАТЬ: я ответил на это в своем iPhone, поэтому я не мог вдаваться в подробности.

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

Что делает большинство людей, так это сканирует компоненты, которые @Service должны быть загружены root WebApplicationContext , которые могут совпадать с контекстом сервлета диспетчера, но часто это не так.

Позвольте мне привести вам пример:

Обычно вы видите applicationContext.xml с помощью следующего:

 <context:component-scan base-package="com.blah">
    <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
  

За которым следует XML-файл контекста сервлета отправки со следующим:

 <context:component-scan base-package="com.blah" use-default-filters="false">
    <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
  

Обратите внимание, как первый исключает @Controller , а второй явно включает.

При этом, если у вас есть только один WebApplicationContext и он совместно используется с сервлетом диспетчера, тогда вы можете комментировать @Service с помощью @RequestMapping , и это должно работать просто отлично, не то чтобы я это рекомендовал.

Комментарии:

1. как я могу узнать, создал ли spring 2 дублирующих компонента? когда я смогу их увидеть?

2. Аннотирование типа с помощью 2 @Component специализаций само по себе не создает два компонента.

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

4. полезное объяснение @AdamGent

Ответ №2:

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

О каком шаблонном коде вы говорите? @Controller и @RequestMapping просты.

Комментарии:

1. Допустим, у меня есть 10 классов сервисов, каждый из которых содержит 10 методов, которые нужно сделать общедоступными для REST API. Вместо реализации каждого класса сервиса и аннотирования методов для экспорта в качестве REST API, мне нужно создать дополнительные 10 классов контроллеров с 10 методами, каждый из которых имеет тело, которое просто возвращает service.method(param1,param2). Теперь у меня есть два фрагмента кода, которые необходимо синхронизировать — любые изменения в одном требуют изменений в другом (= высокая связь). Если service=controller, зависимости контроллера по-прежнему не связаны с реализацией сервиса и методами, отличными от @RequestMapping.

2. Дело в том, что вы могли бы изменить свой уровень обслуживания, не меняя уровень REST, вы могли бы обработать некоторый случай по умолчанию в вашем уровне обслуживания. То, что вы предлагаете, в основном сводится к отказу от хорошей архитектуры (отделите ядро вашего приложения от внешнего использования) из-за неудобств. Также, когда вам нужно внести изменения в свой уровень обслуживания, это должно быть сложно, поскольку вы меняете суть своего приложения.

Ответ №3:

Могу ли я столкнуться с проблемами, если я просто аннотирую свои @Service классы аннотациями @Controller и @RequestMapping

Вам не нужно аннотировать тип с помощью @Controller , если он аннотирован с помощью @Service . Просто убедитесь, что у типа есть @RequestMapping аннотация. RequestMappingHandlerMapping Который обрабатывает сопоставление методов обработчика ваших контроллеров, проверяет наличие как @Controller , так и @RequestMapping аннотаций на уровне типа. Вам нужно либо.

В остальном это просто вопрос дизайна и разделения задач. На техническом уровне Spring у вас не возникнет никаких других проблем.

(Обратите внимание, что вам придется загрузить компонент через DispatcherServlet ‘s WebApplicationContext , чтобы RequestMappingHandlerMapping получить его.)

Ответ №4:

@Controllers предназначены для делегирования входа и конечной точки одному запросу / ответу.

@Service предназначены для предоставления логики этим @Controllers, логики, которая должна быть неизвестна @Controllers.

В @Controllers вы должны @Автоматически подключать свои зависимости @Services. И в ваших @Services ваши другие логические зависимости, такие как DAO и т.д…

Один типичный Rest @ Controller может выглядеть следующим образом:

 @Controller
public class UserWSController {

    @Autowired
    private UserService userService;

    @RequestMapping(value = "/{userId}")
    @ResponseBody
    public User getUserPublicInfo(@PathVariable int userId) {

        return this.userService.getUserById(userId);
    }

}